JAR を動的にロードするアプリケーションを開発しています。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)
、プログラムは正常に動作します。これは、JAR がすでにロードされた後にJavaが検出できることを意味します。TestClass
そのため、JVM はすべての Exception クラスをプログラムの実行開始時に定義する必要があり、それらが必要なとき (つまり、その特定の try-catch ブロックに達したとき) ではないようです。
なぜこれが起こるのですか?
編集
追加のテストをいくつか実行しましたが、これは確かにかなり奇妙です。これはの完全なソースです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
}