Я разрабатываю приложение, которое динамически загружает JAR, который содержит определение набора классов, которые он использует. Все шло хорошо, пока я не попытался поймать производный от исключения класс, который находится в динамически загруженном JAR.
В следующем фрагменте показана проблема (DynamicJarLoader
- это класс, который фактически загружает JAR; и TestClass
, и MyException
находятся во внешнем JAR):
public static void main(String[] args) {
DynamicJarLoader.loadFile("../DynamicTestJar.jar");
try {
String foo = new TestClass().testMethod("42");
} catch(MyException e) { }
}
Когда я пытаюсь запустить его, я получаю это:
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.
Если я заменим catch(MyException e)
на catch(Exception e)
, программа будет работать нормально. Это означает, что Java может найти TestClass
после того, как JAR уже загружен. Таким образом, похоже, что JVM необходимо определить все классы исключений при запуске программы, а не когда они необходимы (т.е. когда достигнут этот конкретный блок try-catch).
Почему это происходит?
EDIT
Я провел несколько дополнительных тестов, и это действительно довольно странно. Это полный источник MyException
:
package dynamictestjar;
public class MyException extends RuntimeException {
public void test() {
System.out.println("abc");
}
}
Этот код работает:
public static void main(String[] args) {
DynamicJarLoader.loadFile("../DynamicTestJar.jar");
String foo = new TestClass().testMethod("42");
new MyException().test(); //prints "abc"
}
Это не:
public static void main(String[] args) {
DynamicJarLoader.loadFile("../DynamicTestJar.jar");
String foo = new TestClass().testMethod("42");
new MyException().printStackTrace(); // throws NoClassDefFoundError
}
Я должен отметить, что всякий раз, когда я запускаю свои тесты из NetBeans, все идет по плану. Странность начинается только тогда, когда я принудительно убираю внешний Jar из глаз Java и запускаю тестовое приложение из командной строки.
РЕДАКТИРОВАТЬ # 2
Основываясь на ответах, я написал это, что, я думаю, доказывает, что тот, который я принял, действительно прав:
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
}