Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ClassLoader confusion

0 views
Skip to first unread message

Ulrich Scholz

unread,
Jan 27, 2006, 1:03:01 PM1/27/06
to
Dear all,

somehow I'm confused by ClassLoader. Please look at the code below.

First, I create a new ClassLoader cl1, more precisely, an instance of
the subclass MyDomainLoader of ClassLoader. Next, I create an instance
of class MyClass with Class.forName("MyClass", true, cl1). That works
fine.

The problem is: The new instance of MyClass seems to be loaded with
the class loader this.getClass().getClassLoader() and _not_ with the
new class loader cl1 that I provided.

What is wrong here?


Here's the story:

I want to get instances of different classes that have the same name. I
try this the following way
- write the java-code to a file (it's always the same file, it gets
overwritten)
- compile the java file into a class file
- create a new instance of MyDomainLoader which extends ClassLoader
- get an instance of the class by using the new ClassLoader

The problem now is that they don't use the class loaders as expected.

Thanks,

Ulrich


ClassLoader cl1 = new MyDomainLoader();
assertFalse(cl1.equals(this.getClass().getClassLoader())); //
it's a new one!

Class domainClass1 = null;
try
{
domainClass1 = Class.forName("MyClass", true, cl1);
}
catch(Exception e)
{
throw(new PPException(INTERNAL_ERROR, e.toString())); //
never happens
}

ClassLoader dl1 = domainClass1.getClassLoader();

// both succeed but should fail!
assertTrue(dl1.equals(this.getClass().getClassLoader()));
assertFalse(dl1.equals(cl1));


// an inner class

final class MyDomainLoader extends ClassLoader
{
public MyDomainLoader()
{
super();
}
}

Thomas Hawtin

unread,
Jan 27, 2006, 2:27:15 PM1/27/06
to
Ulrich Scholz wrote:
>
> First, I create a new ClassLoader cl1, more precisely, an instance of
> the subclass MyDomainLoader of ClassLoader. Next, I create an instance
> of class MyClass with Class.forName("MyClass", true, cl1). That works
> fine.
>
> The problem is: The new instance of MyClass seems to be loaded with
> the class loader this.getClass().getClassLoader() and _not_ with the
> new class loader cl1 that I provided.

You might find java.net.URLClassLoader a ready made solution (with
file:// URLs).

> final class MyDomainLoader extends ClassLoader
> {
> public MyDomainLoader()
> {
> super();

The no-args ClassLoader constructor uses the system class-loader as a
parent, that is to say the class-loader that (probably) loaded your
application.

Class-loaders typically delegate to their parent before trying to find
the class themselves. So if the class name is available to you
application, the child class-loader wont even attempt to find the class.

You haven't overridden any methods to supply further classes, so no
classes at all can be created belonging to this class-loader.

> }
> }
>

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/

oulan bator

unread,
Jan 27, 2006, 2:30:50 PM1/27/06
to
the problem is that you MUST load the class through your ClassLoader

Class domainClass1 = null;
try
{
domainClass1 = cl1.loadClass("MyClass");

}
catch(Exception e)
{
throw(new PPException(INTERNAL_ERROR, e.toString())); //
never happens
}

AND that in your class loader you must NOT look in the parent (because
then it is the first class that is loaded)

Try with two classes with the same name one called A that outputs "A"
and one called that outputs "B". If A is in the system classpath, your
classloader will always load it, and you won't manage outputing B.

but if you slighly modify your classloader, so that it won't look in
the parent (see the findclass method details) , then you can have both
A, and B that work together.

I've had the same problem, and I've manage doing it. So you can feel
confident, we gonna make it !

Thomas Hawtin

unread,
Jan 27, 2006, 3:01:50 PM1/27/06
to
oulan bator wrote:
> the problem is that you MUST load the class through your ClassLoader

The original poster used the long form of Class.forName to achieve that.

> AND that in your class loader you must NOT look in the parent (because
> then it is the first class that is loaded)

Or it uses a parent without the the class already present. For instance,
by using the other ClassLoader constructor.

oulan bator

unread,
Jan 27, 2006, 2:58:27 PM1/27/06
to
you're right I saw it too late... but it doesn't change the second
argument
thanks for correcting me...

Ulrich Scholz

unread,
Jan 28, 2006, 4:22:22 AM1/28/06
to
| but if you slighly modify your classloader, so that it won't look in
| the parent (see the findclass method details) , then you can have
both
| A, and B that work together.

Yes, I thought of that, too, but I cannot find a solution by myself.
Could you give me a short example / some more hints how such a modified
classloader might look like.

Thank you,

Ulrich

oulan bator

unread,
Jan 28, 2006, 5:12:21 AM1/28/06
to
up the thread later mondeay for instance, I have all the material at
work ...
just look deeply in the javadoc of findClass method :
"Finds the class with the specified binary name. This method should be
overridden by class loader implementations that follow the delegation
model for loading classes, and will be invoked by the loadClass method
after checking the parent class loader for the requested class. The
default implementation throws a ClassNotFoundException."

it's your job NOT to check parent class loader AND
override the loadClass(String name) method so that it calls the
protected Class<?> loadClass(String name, boolean resolve)
with resolve=false !
and that's it
with resolve = true (s

Ulrich Scholz

unread,
Jan 30, 2006, 6:39:04 AM1/30/06
to
Sorry, but I still haven't found a soltion. I did as you suggested.
Below, you find my new class MyClassLoader. But I still don't with what
to overwrite findClass(name), the original implementation simply throws
an exception. How can I find a class "myself"? Do I really have to
load it myself and then use defineClass?

Thanks, Ulrich

final class MyDomainLoader extends ClassLoader
{
public MyDomainLoader()
{
super();
}

protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
return findClass(name);
}

public Class<?> loadClass(String name) throws
ClassNotFoundException
{
return loadClass(name, false);
}
}

oulan bator

unread,
Jan 31, 2006, 12:54:02 PM1/31/06
to
sory I was out of the office today.

- but the rule is that you cannot have your classes in the classpath
(otherwise their gonna be found by the parent).

- in the findClass you MUST look for the bytes by yourself (usually
this is what you really want to do). then call the define class.

- resolve depends on what you want to do: if you want that your class
can be seen from the others classloaders, you must call it with
resolve=true, otherwise (usually for a component) you don't want to
share the class (only instances), the you must call it with
resolve=false (as you did)

tommorrow I'll copy paste a piece of code that works

Ulrich Scholz

unread,
Feb 2, 2006, 8:21:32 AM2/2/06
to
Thank you, code would be perfect - I almost get grey hair

Uli

oulan bator

unread,
Feb 7, 2006, 11:07:37 AM2/7/06
to
/** returns a Class corresponding to the class name. load
* the class with the corresponding byte[] in the MetaComponent.
* @param name the name of the Class
* @author
* @date 4 \ 4 \ 2000
*/
protected Class findClass(String name) throws ClassNotFoundException
{
//System.out.println("finding class in component "+name);
byte[] b=getBytes(classNameToEntry(name) ); //due to zip lookup
//getBytes does the specific par to look for the bytes
if (b==null) throw new ClassNotFoundException("No Class File
found.");//return null;
log.debug("[Loaded "+name+" from Component]");
return defineClass(name, b, 0, b.length);
}

here is the body of my findClass method

0 new messages