ClassNotFound when 运行 main() 通过反射但与 java -jar 一起工作正常
ClassNotFound when running main() through reflection but works fine with java -jar
我有一个 jar 文件,我可以在 java -jar my-jar-file.jar
上正常运行。
但现在我必须使用反射从另一个 java 程序加载主要 class,当我这样做时,我得到一个 ClassNotFoundException: javax.mail.MessagingException
.
我用来执行此操作的代码:
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{new File("my-jar-file.jar").toURI().toURL()});
Class<?> serverClass = loader.loadClass("com.foo.bar.application.MyMain");
Method main = serverClass.getMethod("main", String[].class);
String[] params = new String[]{"-flag", "value"};
main.invoke(null, (Object) params);
堆栈跟踪是这样的(删除了细节):
Exception in thread "main" java.lang.reflect.InvocationTargetException
Caused by: java.lang.NoClassDefFoundError: javax/mail/MessagingException
Caused by: java.lang.ClassNotFoundException: javax.mail.MessagingException
我还尝试将 System.getProperty("java.class.path")
中的条目添加到我传递给 class 加载程序的 URL
数组中,但也没有成功。
这个错误对我来说似乎是合理的,因为 jar 文件不包含 javax.mail.MessagingException
(实际上不包含 javax.mail
包)但是当我只做 java -jar my-jar-file.jar
时它是如何工作的?
我该如何解决这个问题?谢谢
编辑:
添加了MANIFEST.MF内容:
Manifest-Version: 1.0
Main-Class: com.foo.bar.application.MyMain
Implementation-Version: 1.5.4
编辑 2:
另外值得一提的是,jar 文件在 META-INF
目录中包含一个 javamail.providers
文件。假设这以某种方式使该 jar 工作,但我如何以编程方式执行相同的操作?
javamail.providers
内容:
# AWS Mail Provider
protocol=aws; type=transport; class=com.amazonaws.services.simpleemail.AWSJavaMailTransport; vendor=Amazon Web Services LLC;
好的,我通过添加 Thread.currentThread().setContextClassLoader(loader);
:
解决了这个问题
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{new File("my-jar-file.jar").toURI().toURL()});
Thread.currentThread().setContextClassLoader(loader);
Class<?> serverClass = loader.loadClass("com.foo.bar.application.MyMain");
Method main = serverClass.getMethod("main", String[].class);
String[] params = new String[]{"-flag", "value"};
main.invoke(null, (Object) params);
现在一切都按预期工作,我不再得到 ClassNotFoundException
,但我仍然不太明白为什么会这样。在我看来,它试图用不同的 ClassLoader
加载额外的 classes/resources,因此未能做到这一点,通过调用 setContextClassLoader
我明确表示要使用提供的 ClassLoader
.
我有一个 jar 文件,我可以在 java -jar my-jar-file.jar
上正常运行。
但现在我必须使用反射从另一个 java 程序加载主要 class,当我这样做时,我得到一个 ClassNotFoundException: javax.mail.MessagingException
.
我用来执行此操作的代码:
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{new File("my-jar-file.jar").toURI().toURL()});
Class<?> serverClass = loader.loadClass("com.foo.bar.application.MyMain");
Method main = serverClass.getMethod("main", String[].class);
String[] params = new String[]{"-flag", "value"};
main.invoke(null, (Object) params);
堆栈跟踪是这样的(删除了细节):
Exception in thread "main" java.lang.reflect.InvocationTargetException
Caused by: java.lang.NoClassDefFoundError: javax/mail/MessagingException
Caused by: java.lang.ClassNotFoundException: javax.mail.MessagingException
我还尝试将 System.getProperty("java.class.path")
中的条目添加到我传递给 class 加载程序的 URL
数组中,但也没有成功。
这个错误对我来说似乎是合理的,因为 jar 文件不包含 javax.mail.MessagingException
(实际上不包含 javax.mail
包)但是当我只做 java -jar my-jar-file.jar
时它是如何工作的?
我该如何解决这个问题?谢谢
编辑:
添加了MANIFEST.MF内容:
Manifest-Version: 1.0
Main-Class: com.foo.bar.application.MyMain
Implementation-Version: 1.5.4
编辑 2:
另外值得一提的是,jar 文件在 META-INF
目录中包含一个 javamail.providers
文件。假设这以某种方式使该 jar 工作,但我如何以编程方式执行相同的操作?
javamail.providers
内容:
# AWS Mail Provider
protocol=aws; type=transport; class=com.amazonaws.services.simpleemail.AWSJavaMailTransport; vendor=Amazon Web Services LLC;
好的,我通过添加 Thread.currentThread().setContextClassLoader(loader);
:
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{new File("my-jar-file.jar").toURI().toURL()});
Thread.currentThread().setContextClassLoader(loader);
Class<?> serverClass = loader.loadClass("com.foo.bar.application.MyMain");
Method main = serverClass.getMethod("main", String[].class);
String[] params = new String[]{"-flag", "value"};
main.invoke(null, (Object) params);
现在一切都按预期工作,我不再得到 ClassNotFoundException
,但我仍然不太明白为什么会这样。在我看来,它试图用不同的 ClassLoader
加载额外的 classes/resources,因此未能做到这一点,通过调用 setContextClassLoader
我明确表示要使用提供的 ClassLoader
.