Устранение неполадок при открытии банки JVM

У меня есть крошечная Java-программа "Test.java", которая опирается на класс "TestLib", который находится в отдельном файле jar в том же каталоге.

Структура "Проекта":

$ ls
Test.java   Test.class   testlib.jar

Test.java и testlib.jar - это заглушки, которые воспроизводят проблему с classpath, которую я вижу в гораздо более крупном приложении. Все, что делает Test.java, - это создание экземпляра класса из testlib.jar и выход:

import com.TestLib;

public class Test {
    public static void main(String[] args) {
        System.out.println("Before instantiating testlib");
        new TestLib();
        System.out.println("After instantiating testlib");
    }
}

У моего тестового фляги есть класс тестовой библиотеки:

$ unzip -l testlib.jar
...
com/TestLib.class
...

(Jar содержит много других классов и файлов метаинформации, здесь опущено)

Я могу скомпилировать этот маленький проект с: javac Test.java -classpath .:testlib.jar

Я пытаюсь запустить его с помощью команды java -classpath .:testlib.jar Testи получите вывод:

Before instantiating testlib
Exception in thread "main" java.lang.NoClassDefFoundError: com/TestLib at Test.main(Test.java:6)

Он не может найти "TestLib"!

Интересно, когда я добавляю -verbose флаг моего вызова Java, я вижу, что он никогда даже не открывает мою библиотеку JAR для поиска там TestLib:

$ java -verbose -classpath .:testlib.jar Test 2>&1 | grep "Opened"
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jsse.jar]
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jce.jar]

Что определяет, открывает ли JVM файл jar для поиска отсутствующего класса? Существуют ли какие-либо META-INF или другое содержимое банки, которое препятствует открытию банки JVM? Какие действия следует предпринять для устранения неполадок, почему "TestLib" не найден во время выполнения?

1 ответ

В моем случае я видел это поведение из-за META-INF/INDEX.LIST файл присутствует в моем JAR.

Этот файл (если имеется) содержит список файлов классов, доступных в JAR. Мой файл INDEX.LIST был неполным и не упоминал мой TestLib учебный класс. Поэтому, когда ClassLoaders пришел посмотреть, они поверили в список содержимого банку в INDEX.LISTи сообщил, что они не смогли найти класс.

(Я закончил с неполным INDEX.LIST из-за какого-то нетрадиционного (читай, некорректного) использования плагина Gradle "shadow". По умолчанию плагин shadow удаляет все файлы INDEX.LIST при создании затененного фляги, но я случайно настроил его так, чтобы он этого не делал. Так что, если вы видите такое поведение в затененной банке, это, вероятно, причина.)

Другие вопросы по тегам