当我在子目录中创建 jar 文件时,bcprov-jdk15on-159.jar 中的 BouncyCaSTLeProvider
类加载失败,并出现 ClassNotFoundException
。我认为创建 jar 文件的位置不应该对其内容和行为产生影响。
这是创建工作 jar 的示例。
$ jar cfm MyProject.jar Manifest.txt Main.class bcprov-jdk15on-159.jar
$ java -jar MyProject.jar
hello provider: BC version 1.59
下面是一个示例,其中使用完全相同的输入文件运行 jar,但 jar 文件目标不同,导致 jar 失败。
$ jar cfm dist/MyProject.jar Manifest.txt Main.class bcprov-jdk15on-159.jar
$ java -jar dist/MyProject.jar
Error: Unable to initialize main class Main
Caused by: java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider
这是文件Manifest.txt
Manifest-Version: 1.0
Main-Class: Main
Class-Path: bcprov-jdk15on-159.jar
这是使用 BouncyCaSTLeProvider
类的 Main.java
文件。
public class Main {
public static void main(String... arg) {
java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
java.security.Provider p = java.security.Security.getProvider("BC");
System.out.println("hello provider: " + p);
}
}
我在 JDK 8 和 JDK 9 以及 JDK jar 命令(如上所示)和 Ant 的 jar 任务中都看到了这种行为。
我在尝试升级PCSecrets时偶然发现了这个问题。在 Java 9 下工作的密码管理器。
最佳答案
上述失败的原因是Java不会从jar文件中加载bcprov-jdk15on-159.jar
,而是从类路径中加载,类路径似乎根据调用的位置而有所不同 jar 。当生成的 jar 文件与 bcprov-jdk15on-159.jar 位于同一目录中时,它会从该目录加载它,并且命令调用工作正常。当生成的jar文件位于其他目录时,无法加载bcprov-jdk15on-159.jar
并抛出ClassNotFoundException
。 this 中提供了将 jar 包含在 jar 中的解决方案。问题。有趣的是,this answer ,被投票了 26 次,也是基于同样的错误假设。
我通过比较生成的 jar 文件的二进制图像找到了答案。它们似乎仅在 META-INF/MANIFEST.MF
文件的时间戳上有所不同。通过使用命令并行生成两个文件 jar cfm dist/MyProject.jar Manifest.txt Main.class bcprov-jdk15on-159.jar & jar cfm MyProject.jar Manifest.txt Main.class bcprov-jdk15on-159 .jar
我有两个完全相同的 jar 文件,但仍然存在问题。这促使我查看这两个文件的执行环境,而不是文件本身。
关于java - 在子目录中创建 jar 文件时出现 NoClassDefFoundError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49466170/