ClassNotFound通过反射运行main()但与java -jar一起正常工作

时间:2015-06-22 15:02:33

标签: java jar

我有一个jar文件,我可以使用java -jar my-jar-file.jar运行。

但是现在我必须使用反射从另一个java程序加载主类,当我这样做时,我得到一个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);

stacktrace就像这样(删除了细节):

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")中的条目添加到我传递给类加载器的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文件在javamail.providers目录中包含META-INF文件。假设这个以某种方式使该jar工作,但我怎么能以编程方式做同样的事情?

javamail.providers内容:

# AWS Mail Provider
protocol=aws; type=transport; class=com.amazonaws.services.simpleemail.AWSJavaMailTransport; vendor=Amazon Web Services LLC;

1 个答案:

答案 0 :(得分:0)

好的,我通过添加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加载其他类/资源,因此未能这样做,并且通过调用setContextClassLoader我明确表示要使用提供的{ {1}}。