IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Java ClassLoader question
I have the following scenario. An application A is loaded by Classloader A. Application B is loaded by classloader B which is under Classloader A, meaning, Classloader B's parent is A.

Given this scenario, Application B can see the classes from application A because B's classloader delegates to A. What happens in the following scenario:
B calls A (B can see A because B's classloader delegates to A). A then tries to call B. To do this A needs to load classes from B. The class load fails with a class not found exception, and I understand why. A uses it's own classloader and therefore loads classes from either a parent classloader or it's own. B's classloader is further down the hierarchy and is therefore not visible to A. Is there any elegant solution to this kind of issue? It seems very strange that B can call A but A cannot call back to B.

I've managed to sort of work around this. If I pass B's classloader to A, then A can use that classloader to creat an instance of B. However, everything needs to be done using reflection. A cannot directly reference B, because A doesn't know about B. This is really frustrating, I have an instance of B but can't cast it to B because I get a ClassNotFound Exception. Any ideas? Below is code that
illustrates the problem:
URL[] urlsToLoadFrom = new URL[]{new URL("file:///C:/temp/subdir/")};
URLClassLoader loader1 = new URLClassLoader(urlsToLoadFrom);
URL[] urlsToLoadFrom2 = new URL[]{new URL("file:///C:/temp/subdir1/")};
URLClassLoader loader2 = new URLClassLoader(urlsToLoadFrom2,loader1);
URL[] urls = loader1.getURLs();
Class cls2 = Class.forName("ClassloaderServerTest",true,
loader1);
Class cls1 = Class.forName("ClassloaderClientTest",true,
loader2);
Object cst = cls2.newInstance();
Object cct = cls1.newInstance();

up to here I am fine, I have instances of my 2 classes. But if I try
the following:
ClassloaderClientTest client = (ClassloaderClientTest)cct;
I geta ClassNotFound Exception. The only way I can call any methods is
to use reflection. That really sucks.

The following works but is really ugly:
Class[] params = new Class[1];
params[0] = cls2;
Object[] methodParams = new Object[1];
methodParams[0] = cst;
Method testMethod = cls1.getMethod("test",params);
testMethod.invoke(cct, methodParams);

I found another workaround, namely use an interface that class A does know about. The code would be something like this:
ClassLoaderTestServerInterface cst = (ClassLoaderTestServerInterface)cls2.newInstance();
ClassLoaderTestClientInterface cct = (ClassLoaderTestClientInterface)cls1.newInstance();

What is also really strange is the following. Given the original scenario above, B calls A and passes A a parameter C. C's classloader (assuming C is some non-trivial object) will be B's classloader which is not visible to A, yet the parameter gets passed and A can see it and use it even though it is from a completely different and unaccessible classloader. How does that work?
Expand Edited by bluke May 5, 2003, 11:12:55 AM EDT
New Re: Java ClassLoader question
I've actually run into this problem before, and, unfortunately, to my knowledge, there is no real clean work-around (outside of the use of reflection). The other complication is that, even if you could get both classloaders to load the same class, they'd be different classes (not compatible).

So, for your wierd situation at the end, my guess is that that can't happen (I've tried and haven't been able to get that to work). You can always pass an Object around, but you can't do much with it (so, my guess is that, in your last situation, the classpath or something allowed that to happen, as it shouldn't happen, normally).

It's really tricky stuff, to be sure. Unfortunately, it's a limitation of the Java platform (for good or bad reasons...).

Now, something to look into is, if you're writing the classloaders, yourself, you can control over them and how they load classes. There may be an "in" in that situations, depending upon the circumstances. In my case, it wasn't enough.

Best of luck with it.

Dan
New Class loaders are an ugly kludge
And in my experience, I just make sure I load everything into one class loader (with a null parent). It seems to work pretty well.

It does sort of make sense that A is restricted for working with things in B but not the other way around. Because you have to remember that a class loader is a namespace or scope. Since A is B's parent, B has access to A but not vice versa.

By way of illustration they work (a little) like this
{ // A scope
int i = 5;
{ // B scope
int j = 6;
i = 7; // OK, B inherits A's scope
}
j = 8; // no good - j out of scope - not visible
}

What is also really strange is the following. Given the original scenario above, B calls A and passes A a parameter C. C's classloader (assuming C is some non-trivial object) will be B's classloader which is not visible to A, yet the parameter gets passed and A can see it and use it even though it is from a completely different and unaccessible classloader. How does that work?


I'm not sure I get it - but IIUC - when you pass C - what is the type of the reference that A sees and where is that type defined (not the concrete type of C - but its apparent type to A)? That is sort of the key. If the apparent type (Object for instance), is visible to A then it can use it (which is why you can do reflection tricks). Its kind of a hole in the system I think.




"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
Expand Edited by tuberculosis Aug. 21, 2007, 06:33:01 AM EDT
New Re: Class loaders are an ugly kludge
Unfortunately I cannot ensure that they will all be in one classloader as the code is running in an application server where ever application ahs it's own classloader.
New OK
But why do classes in the parent loader know about classes in the child loader?

Seems like a partitioning problem to me.



"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
Expand Edited by tuberculosis Aug. 21, 2007, 06:37:56 AM EDT
New It is a long story
Unfortunately it is not up to us to partition the system, the system is already partitioned this way and we need to work with it.
New And a sad one I'll bet
as long as you're screwed and needing to use lots of reflection - you might try using BeanShell and writing scripts in that where the reflection madness is required.




"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
Expand Edited by tuberculosis Aug. 21, 2007, 12:41:24 PM EDT
     Java ClassLoader question - (bluke) - (6)
         Re: Java ClassLoader question - (dshellman)
         Class loaders are an ugly kludge - (tuberculosis) - (4)
             Re: Class loaders are an ugly kludge - (bluke) - (3)
                 OK - (tuberculosis) - (2)
                     It is a long story - (bluke) - (1)
                         And a sad one I'll bet - (tuberculosis)

I can use his toes to plug my holes.
204 ms