摘要: 从正在运行的Java程序加载jar会导致由NoClassDefFoundError
引起的ClassNotFoundException
由类间依赖性引起(例如import
}语句)。我该如何解决这个问题?
更详细的问题:
我正在尝试以编程方式加载jar文件 - 让我们调用它" Server" - 通过我自己的Java程序进入Java虚拟机 - 让我们称之为" ServerAPI" - 并使用扩展和一些其他技巧来修改Server的行为并与之交互。 ServerAPI依赖于Server,但如果Server不存在,ServerAPI仍然必须能够从网站运行和下载Server。
为了避免因ServerAPI加载而导致的错误而不满足Server的依赖关系,我已经制作了一个启动器 - 让我们调用它" Launcher" - 用于下载服务器并根据需要设置ServerAPI,然后加载Server和ServerAPI,然后运行ServerAPI。
但是,当我尝试从Launcher加载jar时,我会收到错误,因为ClassLoader无法解析文件中其加载所依赖的类所依赖的其他类。简而言之,如果我尝试加载类A
,如果A
导入B
,则会抛出错误,因为我还没有加载B
。但是,如果B
也导入A
,我就会陷入困境,因为我无法弄清楚如何一次加载两个类,或者如何在没有JVM运行验证的情况下加载类
为什么所有限制都让我遇到了这个问题:
我正在尝试修改并添加到Server的行为,但由于复杂的法律原因,我无法直接修改程序,因此我创建了依赖的ServerAPI,并且可以从外部调整Server的行为。
但是,出于更复杂的法律原因,Server和ServerAPI不能简单地一起下载。 Launcher(见上文)必须与ServerAPI一起下载,然后Launcher需要下载Server。最后,可以使用Server作为依赖项运行ServerAPI。这就是为什么这个问题如此复杂的原因。
此问题也适用于项目的后续部分,该部分将涉及基于插件的API接口,该接口需要能够在运行时从jar文件加载和卸载插件。
我已就这个问题做过研究:
我已经阅读并且未能得到以下方面的帮助:
等等。没有任何效果。
//编辑: 到目前为止我已尝试过:
我尝试使用URLClassLoaders使用JarEntries
JarFile
加载jar,类似于this question。我尝试使用并调用URLClassLoader
的{{1}}方法并创建了一个扩展loadClass(String)
的类,以便我可以利用URLClassLoader
来尝试强制loadClass(String, boolean resolve)
解析它加载的所有类。两种方式,我都有同样的错误:
ClassLoader
// END EDIT
//编辑2:
以下是我在尝试解析类时加载类的代码示例。这是我在一个扩展I couldn't find the class in the JarEntry!
entry name="org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.class"
class name="org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter"
java.lang.NoClassDefFoundError: javax/persistence/AttributeConverter
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at Corundum.launcher.CorundumClassLoader.load(CorundumClassLoader.java:52)
at Corundum.launcher.CorundumLauncher.main(CorundumLauncher.java:47)
Caused by: java.lang.ClassNotFoundException: javax.persistence.AttributeConverter
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 12 more
的类中。在以URLClassLoader
开头的行上,我尝试使用true和false作为布尔参数;两次尝试都导致了同样的错误。
Class<?> clazz = loadClass(
// END EDIT 2
我意识到必须有一个简单的解决方案,但对于我的生活,我似乎无法找到它。任何帮助都会让我永远感激不尽。谢谢。
答案 0 :(得分:2)
令人尴尬的是,我发现答案是错误信息说实话。 javax.persistence.AttributeConverter
,加载器声称的类不存在,不在jar中。
我通过只加载主类和ClassLoader
所有引用类来解决这个问题,实质上是加载程序中使用的jar中的所有类,这就是我所需要的。
现在,我可以发誓我之前检查过这个并找到了这个课程;我想我在检查时必须实际检查过该类的Apache开源存储库而不是实际的服务器。我不记得了。
无论如何,AttributeConverter
都缺失了。我不知道他们是如何或为什么设法编译一个缺少依赖项的jar,但我猜他们的主要进程从不使用代码的那部分,所以它永远不会抛出错误。
我很遗憾浪费每个人的时间......包括我自己的。我一直坚持这个问题一段时间了。
这个故事的道德:
如果您正在尝试加载可执行jar,请不要在jar中加载所有类,除非您确实需要。只需加载主类;这将加载程序运行所需的所有内容。
<强> //编辑:强>
我现在已经开始遇到相同的错误,但是在我尝试从加载的类调用方法之前它不会出现。问题显然仍然存在。请低估并忽略这个答案。