Which class loader should be recorded as initiating loader?
ravenex
ravenex at qq.com
Sat Oct 15 06:18:17 PDT 2011
Hi all,
I've long had an impression that all class loaders in an loadClass() chain should be recorded as initiating loaders. That knowledge comes from Inside the Java Virtual Machine, 2nd Edition [1]:
But it looks like that's an incorrect impression.
According to the JVMS2e 5.3.2 [2], the "Otherwise" paragraph, only when the JVM initiates a class loading process, the loader directly invoked by the JVM will be recorded as the initiating loader; the ones in the middle of the delegation chain won't be recorded. A loader whose loadClass() is called explicitly (and successfully completed) from Java code isn't necessarily recorded as an initiating loader.
Using the example in [1] in the "Now imagine" paragraph, only Cindy should be an initiating loader of java.io.FileReader; neither Mom nor Grandma should be recorded as an initiating loader.
I've tried writing an actual code to emulate the example, and on JDK6, it shows the description in [1] is wrong.
-----------------------------------------------
TestInitiatingLoader.java
import java.io.*;
import java.net.*;
public class TestInitiatingLoader {
public static void main(String[] args) throws Exception {
Grandma grandma = new Grandma();
Mom mom = new Mom(grandma);
Cindy cindy = new Cindy(mom);
cindy.loadClass("Dummy").newInstance(); // force class init
final String reader = "java.io.FileReader";
printStats(grandma, reader); // false
printStats(mom, reader); // false
printStats(cindy, reader); // true
}
private static void printStats(LoadedClassQueryable loader, String name) {
System.out.printf("Is %s an initiating loader of %s: %b\n",
loader.getClass().getName(),
name,
loader.foundLoadedClass(name));
}
}
interface LoadedClassQueryable {
boolean foundLoadedClass(String name);
}
class Cindy
extends URLClassLoader
implements LoadedClassQueryable {
public Cindy(ClassLoader parent) {
super(makeArgs(), parent);
}
private static URL[] makeArgs() {
try {
return new URL[] { new File(".").toURI().toURL() };
} catch (Exception e) {
e.printStackTrace();
return new URL[] { };
}
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if ("Dummy".equals(name)) {
// force Cindy to load this Dummy class
return findClass("Dummy");
}
return super.loadClass(name);
}
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
class Mom
extends ClassLoader
implements LoadedClassQueryable {
public Mom(ClassLoader parent) {
super(parent);
}
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
// use system class loader as parent
class Grandma
extends ClassLoader
implements LoadedClassQueryable {
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
-----------------------------------------------
Dummy.java
import java.io.*;
public class Dummy {
static {
// Dummy should be loaded by Cindy.
// So Cindy will be recorded as an initiating loader for java.io.FileReader
try {
new FileReader("Dummy.class").close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
-----------------------------------------------
Could anybody clarify which loaders are supposed to be recorded as an initiating loader?
[1]: http://www.artima.com/insidejvm/ed2/linkmod3.html
[2]: http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#79441
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/jdk6-dev/attachments/20111015/ec794216/attachment.html
More information about the jdk6-dev
mailing list