由于 JRE 8u232,JNI 在签名的 JAR 中找不到类

And*_*s N 6 java java-native-interface

我有一个带有签名 JAR 的 Java 应用程序,其中包含所有类文件和资源。该应用程序附带一个捆绑的 JRE 和一个可执行文件。此可执行文件是用 C++ 编写的,并使用 JNI 加载 VM 并启动应用程序。这在过去完美无缺。

从 JRE 8u232(例如 Azul,还有来自 Oracle 的 8u231)开始,应用程序不再运行,因为在 JNI 的FindClass()函数中找不到指定的主类。它返回一个空指针,然后当我调用该ExceptionDescribe()函数时,它会显示 Java 方法中发生的 NPE JarVerifier::processEntry

Exception in thread "main" java.lang.NullPointerException
    at java.util.jar.JarVerifier.processEntry(JarVerifier.java:303)
    at java.util.jar.JarVerifier.update(JarVerifier.java:230)
    at java.util.jar.JarFile.initializeVerifier(JarFile.java:383)
    at java.util.jar.JarFile.ensureInitialization(JarFile.java:612)
    at java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
    at sun.misc.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:991)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
Run Code Online (Sandbox Code Playgroud)

当我从 JAR 的 META-INF 文件夹中删除 *.RSA 和 *.SF 文件时,它又可以工作了。当我从 JRE 的“bin”文件夹调用“java”可执行文件时,它也可以工作,如下所示:

java -cp "path/to/my/jar" org.company.name.MyMainclass
Run Code Online (Sandbox Code Playgroud)

在我看来,导致此问题的 Java 8(或更新版本)发生了一些变化。但是我找不到原因。这里可能是什么问题?

更新:

我使用 JarVerifier 类进行了一些远程调试,并观察到以下情况:

  • JarVerifier::processsigFileData多次访问哈希图(第 303 行)get()
  • 在某个时间点JarVerifier::doneWithMeta被调用,它在get()再次调用其方法之前将映射设置为 null
  • 这仅在通过 JNI 启动应用程序时发生

更新 2:

我找出了导致问题的原因并让我的应用程序再次运行,但我不明白为什么。启动应用程序的可执行文件读取带有多个参数的文本文件以传递给 VM(例如系统属性、主类名称等)。一个参数将系统属性设置为同一目录中java.util.logging.config.filelogging.properties文件。该属性文件的开头是这样的:

handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
.handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
Run Code Online (Sandbox Code Playgroud)

这些语句和处理程序类是 10 年前编写的。当我删除“.handlers”语句时,我的应用程序可以正常工作并且日志记录似乎仍然可以正常工作。

最让我困惑的是,在应用程序启动时,这条线将如何导致 JarVerifier 类中的 NullPointerException。怎么可能?有什么联系?

Sco*_*ott 3

LogManager文档建议无效,因为它缺少记录器说明符.handlers

属性“<logger>.handlers”。这定义了一个空格或逗号分隔的类名列表,供处理程序类加载并注册为指定记录器的处理程序。每个类名必须是具有默认构造函数的 Handler 类。请注意,这些处理程序在首次使用时可能会延迟创建。

我的猜测是 8u232 引入了一项更改,不再处理(或推断)丢失的记录器名称。要么可能有一个映射到null不存在的映射和/或对null键控记录器的新引用。