У меня есть приложение Java с подписанным JAR, которое содержит все файлы классов и ресурсы. Приложение поставляется с JRE и исполняемым файлом. Этот исполняемый файл написан на C ++ и использует JNI для загрузки виртуальной машины и запуска приложения. В прошлом это работало безупречно.
Начиная с JRE 8u232 (например, Azul, но также 8u231 из Oracle), приложение больше не запускается, поскольку указанный основной класс не может быть найден с помощью функции FindClass()
JNI. Он возвращает нулевой указатель, и когда я затем вызываю функцию ExceptionDescribe()
, он показывает NPE, возникающий в методе Java 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)
Когда я удаляю * .RSA и * .SF файлы из папки JAR META-INF снова работают. Это также работает, когда я вызываю «java» исполняемый файл из папки «bin» JRE, например:
java -cp "path/to/my/jar" org.company.name.MyMainclass
Мне кажется, что что-то изменилось относительно Java 8 (или новее) ) что вызывает эту проблему. Однако я не могу найти причину. В чем здесь может быть проблема?
Обновление:
Я сделал некоторую удаленную отладку с классом JarVerifier и заметил следующее:
-
JarVerifier::process
обращается к хэш-карте sigFileData
несколько раз (строка № 303) с помощью get()
- в некоторой точке, вызывается
JarVerifier::doneWithMeta
, что устанавливает карту в null, прежде чем ее метод get()
будет вызван снова - это происходит только при запуске приложения через JNI
Обновление 2:
Я выяснил причину проблемы и получил мое приложение снова работать, но я не понимаю почему. Исполняемый файл, который запускает приложение, читает текстовый файл с несколькими параметрами для передачи на виртуальную машину (например, системные свойства, имя основного класса и т. Д. c). Один параметр устанавливает системное свойство java.util.logging.config.file
в файл logging.properties
в том же каталоге. Этот файл свойств начинается следующим образом:
handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
.handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
Эти операторы и класс обработчика были записаны 10 лет go. Когда я удаляю оператор «.handlers», мое приложение работает, и ведение журнала все еще работает нормально.
Больше всего меня удивляет то, как эта строка вызовет исключение NullPointerException в классе JarVerifier при запуске приложения. Как это может быть? Какая связь?