Note that there are some explanatory texts on larger screens.

plurals
  1. POIn Java, why do Exception classes need to be available to the classloader before they're necessary?
    text
    copied!<p>I'm developing an application that dynamically loads a JAR, which contains the definition of a bunch of classes it uses. Everything went fine until I tried to catch an Exception-derived class that's in the dynamically loaded JAR.</p> <p>The following snippet shows the issue (<code>DynamicJarLoader</code> is the class which actually loads the JAR; both <code>TestClass</code> and <code>MyException</code> are in the external JAR):</p> <pre><code>public static void main(String[] args) { DynamicJarLoader.loadFile("../DynamicTestJar.jar"); try { String foo = new TestClass().testMethod("42"); } catch(MyException e) { } } </code></pre> <p>When I try to run it, I get this:</p> <pre><code>Exception in thread "main" java.lang.NoClassDefFoundError: dynamictestjar/MyException Caused by: java.lang.ClassNotFoundException: dynamictestjar.MyException at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) Could not find the main class: dynamicjartestapp.Main. Program will exit. </code></pre> <p>If I replace <code>catch(MyException e)</code> with <code>catch(Exception e)</code>, the program runs fine. This means that Java <em>is</em> able to find <code>TestClass</code> after the JAR has already been loaded. So it appears that the JVM needs all Exception classes to be defined when the program starts running, and not when they're needed (i.e. when that particular try-catch block is reached).</p> <p>Why does this happen?</p> <p><strong>EDIT</strong></p> <p>I've run some additional tests, and this is indeed quite odd. This is the full source of <code>MyException</code>:</p> <pre><code>package dynamictestjar; public class MyException extends RuntimeException { public void test() { System.out.println("abc"); } } </code></pre> <p>This code runs:</p> <pre><code>public static void main(String[] args) { DynamicJarLoader.loadFile("../DynamicTestJar.jar"); String foo = new TestClass().testMethod("42"); new MyException().test(); //prints "abc" } </code></pre> <p>This doesn't:</p> <pre><code> public static void main(String[] args) { DynamicJarLoader.loadFile("../DynamicTestJar.jar"); String foo = new TestClass().testMethod("42"); new MyException().printStackTrace(); // throws NoClassDefFoundError } </code></pre> <p>I should point out that whenever I run my tests from NetBeans, everything goes according to plan. The weirdness begins only when I forcefully remove the external Jar from Java's eyes and run the test app from the command line.</p> <p><strong>EDIT #2</strong></p> <p>Based on the answers, I wrote this, which I think proves the one I accepted is indeed right:</p> <pre><code> public static void main(String[] args) { DynamicJarLoader.loadFile("../DynamicTestJar.jar"); String foo = new TestClass().testMethod("42"); class tempClass { public void test() { new MyException().printStackTrace(); } } new tempClass().test(); // prints the stack trace, as expected } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload