Reputation: 2161
I'm trying to define a custom ClassLoader.
public class ExampleLoader extends ClassLoader
{
public Class<?> findClass(String name) throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.findClass(name);
}
public Class<?> loadClass(String name, boolean b)
throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.loadClass(name, b);
}
}
And of course my code to test it:
public class Tester
{
public static void main(String[] args)
{
Thread t = new FooThread();
t.setContextClassLoader(new ExampleLoader());
t.start();
}
}
class FooThread extends Thread
{
public void run()
{
new RandomClass();
}
}
The problem is that my lines never get printed. Clearly I'm missing something.
Upvotes: 6
Views: 274
Reputation: 1109222
This is related to bug 4868493. Here's a cite of relevance:
Unfortunately the documentation for
getContextClassLoader
andsetContextClassLoader
might lead one to the conclusion that the submitter's code should work as expected.
However, there is a basic rule in class loading - no class can ever automatically load a class which is "downstream", i.e. which cannot be directly loaded by that class'
ClassLoader
or one of its ancestorClassLoaders
.
This is described in a number of places. For example, meditate on the white paper available here: http://www.javageeks.com/Papers/ClassForName/index.html to gain enlightenment.
The key point seems to be that the context class loader is not used automatically by the Java language. It's only a conventional place to store the context class loader so that other classes can use it with the 3-argument form of
Class.forName
.
The spec for
Thread.getContextClassLoader
andThread.setContextClassLoader
should be clarified, and the meaning of "context class loader" should be clarified. Re-classifying as a doc bug.
The spec has not been clarified yet.
To get it to work what you initially want, replace new RandomClass()
by
Class.forName(RandomClass.class.getName(),
true,
getContextClassLoader()).newInstance();
This prints, contradictorily, the following:
This never gets printed
Upvotes: 6
Reputation: 14505
Normally, all classloaders in a JVM are organized in a hierarchy such that every classloader (except for the primordial classloader that bootstraps the entire JVM) has a single parent. When asked to load a class, every compliant classloader is expected to delegate loading to its parent first and attempt to define the class only if the parent fails.
Same thing is happening in your case. "RandomClass" is to be loaded, ContextClassLoader delegates to its parent an so on. And one of parent class loader was able to load "RandomClass" (RandomClass was in classpath of parent). Because of this reason your SOP doesn't show up.
Reference following article little old but good:
http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1
Upvotes: 0