<DIV>Hi all,</DIV>
<DIV>&nbsp;</DIV>
<DIV>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]:</DIV>
<DIV>But it looks like that's an incorrect impression.</DIV>
<DIV>&nbsp;</DIV>
<DIV>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.</DIV>
<DIV>&nbsp;</DIV>
<DIV>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.</DIV>
<DIV>I've tried writing an actual code to emulate the example, and on JDK6, it shows the description in [1] is wrong.</DIV>
<DIV>&nbsp;</DIV>
<DIV>-----------------------------------------------</DIV>
<DIV>TestInitiatingLoader.java</DIV>
<DIV>&nbsp;</DIV>
<DIV>import java.io.*;<BR>import java.net.*;</DIV>
<DIV>&nbsp;</DIV>
<DIV>public class TestInitiatingLoader {<BR>&nbsp; public static void main(String[] args) throws Exception {<BR>&nbsp;&nbsp;&nbsp; Grandma grandma = new Grandma();<BR>&nbsp;&nbsp;&nbsp; Mom mom = new Mom(grandma);<BR>&nbsp;&nbsp;&nbsp; Cindy cindy = new Cindy(mom);<BR>&nbsp;&nbsp;&nbsp; cindy.loadClass("Dummy").newInstance(); // force class init<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; final String reader = "java.io.FileReader";<BR>&nbsp;&nbsp;&nbsp; printStats(grandma, reader); // false<BR>&nbsp;&nbsp;&nbsp; printStats(mom, reader);&nbsp;&nbsp;&nbsp;&nbsp; // false<BR>&nbsp;&nbsp;&nbsp; printStats(cindy, reader);&nbsp;&nbsp; // true<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; private static void printStats(LoadedClassQueryable loader, String name) {<BR>&nbsp;&nbsp;&nbsp; System.out.printf("Is %s an initiating loader of %s: %b\n",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loader.getClass().getName(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loader.foundLoadedClass(name));<BR>&nbsp; }<BR>}</DIV>
<DIV>&nbsp;</DIV>
<DIV>interface LoadedClassQueryable {<BR>&nbsp; boolean foundLoadedClass(String name);<BR>}</DIV>
<DIV>&nbsp;</DIV>
<DIV>class Cindy<BR>&nbsp;&nbsp;&nbsp; extends URLClassLoader<BR>&nbsp;&nbsp;&nbsp; implements LoadedClassQueryable {<BR>&nbsp; public Cindy(ClassLoader parent) {<BR>&nbsp;&nbsp;&nbsp; super(makeArgs(), parent);<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; private static URL[] makeArgs() {<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new URL[] { new File(".").toURI().toURL() };<BR>&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new URL[] { };<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; @Override<BR>&nbsp; public Class&lt;?&gt; loadClass(String name) throws ClassNotFoundException {<BR>&nbsp;&nbsp;&nbsp; if ("Dummy".equals(name)) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // force Cindy to load this Dummy class<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return findClass("Dummy");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; return super.loadClass(name);<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; @Override<BR>&nbsp; public boolean foundLoadedClass(String name) {<BR>&nbsp;&nbsp;&nbsp; return findLoadedClass(name) != null;<BR>&nbsp; }<BR>}</DIV>
<DIV>&nbsp;</DIV>
<DIV>class Mom<BR>&nbsp;&nbsp;&nbsp; extends ClassLoader<BR>&nbsp;&nbsp;&nbsp; implements LoadedClassQueryable {<BR>&nbsp; public Mom(ClassLoader parent) {<BR>&nbsp;&nbsp;&nbsp; super(parent);<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; @Override<BR>&nbsp; public boolean foundLoadedClass(String name) {<BR>&nbsp;&nbsp;&nbsp; return findLoadedClass(name) != null;<BR>&nbsp; }<BR>}</DIV>
<DIV>&nbsp;</DIV>
<DIV>// use system class loader as parent<BR>class Grandma<BR>&nbsp;&nbsp;&nbsp; extends ClassLoader<BR>&nbsp;&nbsp;&nbsp; implements LoadedClassQueryable {<BR>&nbsp; @Override<BR>&nbsp; public boolean foundLoadedClass(String name) {<BR>&nbsp;&nbsp;&nbsp; return findLoadedClass(name) != null;<BR>&nbsp; }<BR>}<BR>-----------------------------------------------</DIV>
<DIV>Dummy.java</DIV>
<DIV>&nbsp;</DIV>
<DIV>import java.io.*;</DIV>
<DIV>&nbsp;</DIV>
<DIV>public class Dummy {<BR>&nbsp; static {<BR>&nbsp;&nbsp;&nbsp; // Dummy should be loaded by Cindy.<BR>&nbsp;&nbsp;&nbsp; // So Cindy will be recorded as an initiating loader for java.io.FileReader<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FileReader("Dummy.class").close();<BR>&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }<BR>}<BR>-----------------------------------------------</DIV>
<DIV>&nbsp;</DIV>
<DIV>Could anybody clarify which loaders are supposed to be recorded as an initiating loader?</DIV>
<DIV>&nbsp;</DIV>
<DIV>[1]: <A href="http://www.artima.com/insidejvm/ed2/linkmod3.html">http://www.artima.com/insidejvm/ed2/linkmod3.html</A></DIV>
<DIV>[2]: <A href="http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#79441">http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#79441</A></DIV>