Неожиданная `NoClassDefFoundError`, когда дополнительная библиотека не находится в пути к классам, но связанный код не вJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Неожиданная `NoClassDefFoundError`, когда дополнительная библиотека не находится в пути к классам, но связанный код не в

Сообщение Anonymous »

Я пытаюсь использовать компилятор Google Closure из кода Java, но хочу, чтобы он был дополнительной зависимостью (присутствовал во время сборки, но может отсутствовать при развертывании).
У меня возникла проблема: что я получаю NoClassDefFoundError, когда библиотека не находится в пути к классам во время выполнения.
Этого, конечно, можно было бы ожидать, если бы я выполнял код, ссылающийся на символы библиотеки. Но весь такой код никогда не выполняется (за флагом). Фактически, исключение возникает при первом доступе к классу, содержащему этот код.
Я уже немного ломаю голову над этим и думаю, что, возможно, мне не хватает некоторых сведений о семантика загрузки классов в JVM.
Я свел проблему к следующему:

Код: Выделить всё

import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.StrictWarningsGuard;

public class Main {
public static void main(String[] args) {
System.out.println("HelloWorld");
}

private static void thisMethodIsNotCalled() {
new CompilerOptions().addWarningsGuard(new StrictWarningsGuard());
}
}
Единственный код, обращающийся к библиотеке, находится в методе, который никогда не вызывается.
Скомпилировать с помощью (jar, загруженного из maven):

Код: Выделить всё

javac -cp closure-compiler-v20240317.jar Main.java
И при запуске я получаю NoClassDefFoundError:

Код: Выделить всё

$ java Main
Error: Unable to initialize main class Main
Caused by: java.lang.NoClassDefFoundError: com/google/javascript/jscomp/WarningsGuard
Я ожидал, что программа запустится успешно. Нет причин, по которым JVM должна пытаться загрузить какой-либо из классов библиотеки.
Почему это происходит? Я просматривал спецификацию JVM и не понимаю, как загрузка Main приведет к тому, что JVM попытается загрузить символы, указанные в thisMethodIsNotCalled.
Более любопытно, что замена содержимого thisMethodIsNotCalled на следующее не приводит к этой ошибке, поэтому, похоже, это вызвано очень специфическим взаимодействием.

Код: Выделить всё

new StrictWarningsGuard();
new CompilerOptions().addWarningsGuard(null);
Дополнительный контекст
Это происходит с OpenJDK 21 в Ubuntu 24.04:

Код: Выделить всё

$ java -version
openjdk version "21.0.3" 2024-04-16
OpenJDK Runtime Environment (build 21.0.3+9-Ubuntu-1ubuntu1)
OpenJDK 64-Bit Server VM (build 21.0.3+9-Ubuntu-1ubuntu1, mixed mode, sharing)
Но я думаю, что это не относится только к этой версии, я также воспроизводил это с различными другими версиями.

Подробнее здесь: https://stackoverflow.com/questions/785 ... sspath-but
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»