This week's book giveaway is in the Servlets forum.
We're giving away four copies of Murach's Java Servlets and JSP and have Joel Murach on-line!
See this thread for details.
The moose likes Java in General and the fly likes Why getting ClassCastException? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Why getting ClassCastException?" Watch "Why getting ClassCastException?" New topic
Author

Why getting ClassCastException?

Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
I have installed my ClassLoader as the System classloader (using -Djava.system.class.loader). My ClassLoader extends URLClassLoader. In the constructor (the only one called by the bootclasspath loader is: YourClassLoader(ClassLoader parent) ) I call super(URL[] urls, ClassLoader parent) by passing it like so:

When I do the above, I get a class cast exception when I try to cast a class that a class loader instance (in the program below) created to an interface that my class loader defined.

Just to give some more information on the problem: in both cases (passing "parent" to "super()" and passing "null" to "super()"), the ClassLoader of the "Doable" class is always MyClassLoader. Also, I have logging in every method called (when an attempt is made to load or find a class) and it is called for Doable only once - whereupon I define and load the class.
I'm sure I am doing something wrong, but I'm not sure what. Does anyone have any idea what it might be?
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
When I do the above, I get a class cast exception when I try to cast a class that a class loader instance (in the program below) created to an interface that my class loader defined.
I didn't follow that. The interface "Doable" wasn't defined by your class loader uc, was it? I mean, you just created uc; I don't see you loading Doable with it, and even if you did, you couldn't cast to a dynamically defined class like that, would you?
Is Doable defined by the system class loader? Is its classfile accessible from the CLASSPATH? If not, please show just how Doable is defined.
Are you sure that com.something.Test is not on the classpath? Or otherwise accessible by the original system class loader, which is now the parent of your URLClassLoader? The loadClass() method delegates the request to the parent first, so if there is a com.something.Test class file somewhere you've forgotten about (maybe a copy that doesn't implement Doable? or a different Doable?) then it's finding that first, I'd imagine.
Maybe this will tell you something:


"I'm not back." - Bill Harding, Twister
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Don't worry, I'm not that bad.
I know the classpaths are all correct because I'm using ant to run this and have specified everything exactly in jar files (and I double checked what's in each jar file). What makes this tough to figure out/debug is I'm trying to set my classloader as the system classloader and there's not much documentation for how best to do this.
My ClassLoader (the system one) defines the classes and sets their permissions, but only for classes on the class path and only classes that have not yet been loaded (i.e. none of the classes in the bootclasspath or extensions). To do this, I implemented findClass and loadClass (both with/without resolve).
Now I found if I pass the constructor parameter "parent" (which is sun.misc.Launcher$AppClassLoader instance), then when application code tries to load a class that my system classloader already loaded (with loadClass) it does NOT call that method on my classloader, but goes straight to its parent somehow. (I'm not sure how or why it does this, do you know?) When it does that, because that class file is on the class path (and since a classloader below it - i.e. my system class loader - defined that class), the Launcher$AppClassLoader defines the class again! The only way I can figure out to stop this is to set my classloader just below the extensions class loader. In other words set it's parent as parent.getParent() so it's at equal level with Launcher$AppClassLoader.
I'm not sure if I'm describing this properly, but basically when a classloader defines a class, that class is unknowable to the classloader above it (i.e. its parent). For some reason, the structure of the JVM is such that on MOST explicit and implicit calls my system classloader's methods are called and for some of them (it appears to be only if the class was already loaded) it goes straight to the parent of my system classloader.
My guess is that it calls some private/package-access method that is an implementation method on ClassLoader that returns the parent or something - maybe for optimization(?) instead of asking my classloader again. So ONLY if the parent cannot find that class (which the extensions classloader cannot, but the AppClassLoader can), will it consult my system classloader again.
Any idea why this happens? And where I can see this in the JRE code?
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Hey Jim,
I don't know if you saw my reply since this thread got pushed down so low.
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451
Now I found if I pass the constructor parameter "parent" (which is sun.misc.Launcher$AppClassLoader instance), then when application code tries to load a class that my system classloader already loaded (with loadClass) it does NOT call that method on my classloader, but goes straight to its parent somehow. (I'm not sure how or why it does this, do you know?)
Since 1.2, Java has used a delegation model for Classloaders, ie children defer to parents all the way up the chain and if none of the other loaders find the requested class, then the child attempts to load it with its CLASSPATH. Take a look at this article. This has caused us quite a bit of grief at work since on Websphere 5.0, we are dealing with at least six ClassLoaders. Problems arise when a parent knows of one class that has reference to classes that are only known by children.
... So ONLY if the parent cannot find that class (which the extensions classloader cannot, but the AppClassLoader can), will it consult my system classloader again.
That's pretty much it. Which methods did you override in your ClassLoader? Take a look at the source code for ClassLoader in the src.zip that comes with the SDK, it should be in the root of the installation directory. Here is the pertinent loadClass method:


Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius - and a lot of courage - to move in the opposite direction. - Ernst F. Schumacher
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Since 1.2, Java has used a delegation model for Classloaders, ie children defer to parents all the way up the chain and if none of the other loaders find the requested class, then the child attempts to load it with its CLASSPATH. Take a look at this article. This has caused us quite a bit of grief at work since on Websphere 5.0, we are dealing with at least six ClassLoaders. Problems arise when a parent knows of one class that has reference to classes that are only known by children.

Yes, except the problem is that I want this to be the system/application classloader, so it's a bit different than a normal classloader. All non-system/ext classes I want to be defined by my classloader (whether declared explicitly or not). This includes classes on the classpath. This is supposed to be possible, as Java 1.4 is allowing you to use "-Djava.system.class.loader=myloader" but if you keep the parent as the one passed in, i.e. sun.misc.Luancher$AppClassLoader, then your classloader cannot be the classpath loader! Which of course negates the whole point of using that system property in the first place. So I believe I am correct (please do correct me if I;m not) that the only way to have my system loader be the classpath loader (as the system property implies) is to have the extensions loader be its parent and NOT the Launcher$AppClassLoader.
That's pretty much it. Which methods did you override in your ClassLoader? Take a look at the source code for ClassLoader in the src.zip that comes with the SDK, it should be in the root of the installation directory. Here is the pertinent loadClass method:

I overrode loadClass(..) (both versions), findClass().
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451
So I believe I am correct (please do correct me if I;m not) that the only way to have my system loader be the classpath loader (as the system property implies) is to have the extensions loader be its parent and NOT the Launcher$AppClassLoader.
I think you're right. The extension loader is the child of the application loader. So if you set the extension loader as the parent of your loader, it should never find its way to the app loader. I have a little class that may help you investigate some of this. It uses reflection to dump all the classes loaded by a ClassLoader.

[ February 24, 2004: Message edited by: Michael Morris ]
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Why getting ClassCastException?
 
Similar Threads
Adding JAR file to Classpath at Runtime
Class loader Query ??
Stumped on classloading problem! Help!
Loading Classes in at Runtime - NoClassDefFound
Is this how I properly make it use my AppClassLoader?