在子目录

时间:2018-03-24 14:59:56

标签: java jar bouncycastle classnotfoundexception

当我在子目录中创建jar文件时,来自bcprov-jdk15on-159.jarBouncyCastleProvider类无法加载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

这是使用Main.java类的BouncyCastleProvider文件。

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下工作时偶然发现了这个问题。

1 个答案:

答案 0 :(得分:2)

上述失败的原因是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文件仍然行为不端。这促使我查看两个文件执行的环境,而不是文件本身。