java.lang.NoClassDefFoundError: Не удалось инициализировать класс XXX


165
public class PropHolder {
  public static Properties prop;

  static {
    //code for loading properties from file
  }
}

// Referencing the class somewhere else:
Properties prop = PropHolder.prop;

class PropHolderэто мой собственный класс. Класс находится в том же файле JAR основного класса. Так что этого не должно быть, потому что JAR отсутствует в classpath.

Когда я просматриваю файл JAR jar tf myjarfile, я вижу там PropHolder.classперечисленные.

Кстати: код работает нормально на моей локальной машине. Но не смог работать, когда я развернул его с каким-то скриптом на сервере Linux. Поэтому я думаю, что это не проблема кода. Но по какой-то причине. Процесс развертывания очень сложно отследить.

В чем может быть проблема?


Соответствующая структура каталогов в вашем банке соответствует пакету класса?
— Джон Б.

нужно увидеть какой-то источник, многие вещи могут быть причиной этого. например, оператор 'package', но файл фактически не находится по соответствующему пути
— jcomeau_ictx

3
Одной из причин является исключение во время инициализации - есть ли еще какие-либо сообщения об ошибках?
— Майкл Брюер-Дэвис

Ответы:


211

Моя лучшая ставка в том, что здесь есть проблема:

static {
    //code for loading properties from file
}

Казалось бы, возникло какое-то неперехваченное исключение, которое распространялось до самого ClassLoader, пытающегося загрузить класс. Нам понадобится трассировка стека, чтобы подтвердить это.

Либо это, либо это произошло при создании PropHolder.propстатической переменной.


Я сталкиваюсь с одной и той же проблемой снова и снова. Я уверен, что это из-за staticпроблемы. Что нужно сделать, чтобы решить проблему?
— Гадюка

1
Вам нужно будет определить, какое исключение выдается из staticблока. Для его отладки обведите try/catch(Exception e)весь блок и зарегистрируйте исключение. Вам придется исправить это исключение. Обычно исключение регистрируется, но его может быть трудно найти, поскольку оно регистрируется во время загрузки классов, что может произойти очень рано
— Джон Винт

Да, я держал код в try catchблоке, и он сказал Failed to initialize ClassA. Я думаю, что это проблема JVM. Я перезапустил свою систему, а затем все работало нормально. Как решить эту проблему в будущем, не перезагружая мою систему, и решить проблему простым решением.
— Вайпер

Не удалось инициализировать ClassA - это побочный эффект от чего-то другого. Вы будете хотеть посмотреть на, causeесли доступно. A NoClassDefFoundErrorвсегда ассоциируется с другой ошибкой, вам нужно будет найти ее в журналах или попытаться зарегистрировать ее более подходящим образом (например, принудительно войти в новый файл в файловой системе)
— John Vint

Было бы легче отследить, если бы Java выдавала ошибку CouldNotInitializeStaticPartOfClassError или что-то еще. Тогда мы, как разработчик, знали бы, где искать.
— Мартен

126

Вы получаете, java.lang.NoClassDefFoundErrorчто НЕ означает, что ваш класс отсутствует (в этом случае вы получите java.lang.ClassNotFoundException). ClassLoader столкнулся с ошибкой при чтении определения класса при попытке чтения класса.

Поместите try / catch внутри статического инициализатора и посмотрите на исключение. Если вы читаете там какие-то файлы, и они отличаются от вашей локальной среды, это, скорее всего, является причиной проблемы (возможно, файл не найден, нет разрешений и т. Д.).


1
Одно из объяснений состоит в том, что хотя NoClassDefFoundError не подразумевает исключение ClassNotFoundException, оно все еще является возможной причиной NoClassDefFoundError.
— Джон Винт

1
Если бы у вас было ClassNotFoundException, то ClassLoader никогда бы не смог загрузить класс, верно?
— Джеха

4
Класс может загружать другой класс, который не был найден. Причиной в этом случае по-прежнему является ClassNotFoundException
— Джон Винт

1
Я должен был уточнить, я просто имел в виду исключение. GetCause ()
— Джон Винт

1
Этот был действительно полезен здесь, так как я потратил около 20 минут, чтобы убедиться, что JAR (к которому принадлежит класс) включен. Как только я понял, что смотрю в неправильном направлении, я легко понял, что, скорее всего, какой-то класс аннотаций отсутствует и вуаля, объявленный был объявлен как @Stateless, поэтому я просто добавил соответствующую зависимость и смог продолжить. Спасибо за чаевые!
— RAM237

33

NoClassDefFoundError не дает большой подсказки о том, что пошло не так внутри статического блока. Рекомендуется всегда иметь такой блок внутри статического кода инициализации {...}:

static {
  try {

    ... your init code here

  } catch (Throwable t) {
    LOG.error("Failure during static initialization", t);
    throw t;
  }
}

Как это сделать в котлине?
— Марлон

Спасибо за подсказку. В моем случае я получал NPE при статической инициализации линии.
— Абхишек

3

У меня было то же исключение, вот как я решил проблему:

Предпосылки:

  1. Класс Junit (и тест), который расширил другой класс.

  2. ApplicationContext инициализируется с помощью Spring, который инициирует проект.

  3. Контекст приложения был инициализирован в методе @Before

Решение:

Инициируйте контекст приложения из метода @BeforeClass, поскольку родительскому классу также требуются некоторые классы, которые были инициализированы из контекста приложения.

Надеюсь, это поможет.


2

Как уже упоминалось выше, это может быть несколько вещей. В моем случае у меня была статически инициализированная переменная, которая опиралась на отсутствующую запись в моем файле свойств. Добавил отсутствующую запись в файл свойств, и проблема была решена.


1

Всего несколько дней назад я встретил такой же вопрос, как и ваш. Весь код хорошо работает на моей локальной машине, но получается ошибка (noclassdeffound & initialize). Поэтому я публикую свое решение, но я не знаю почему, я просто выдвигаю возможность. Я надеюсь, что кто-то знает, это объяснит. @ Джон Винт Во-первых, я покажу вам мою проблему. Мой код имеет статическую переменную и статический блок оба. Когда я впервые столкнулся с этой проблемой, я попробовал решение Джона Винта и попытался поймать исключение. Однако я ничего не поймал. Поэтому я подумал, что это потому, что статические переменные (но теперь я знаю, что это одно и то же) и до сих пор ничего не нашли. Итак, я пытаюсь найти разницу между машиной Linux и моим компьютером. Затем я обнаружил, что эта проблема возникает только тогда, когда несколько потоков выполняются в одном процессе (кстати, на машине linux есть два ядра и два процесса). Это означает, что если в одном и том же процессе выполняются две задачи (обе используют код со статическим блоком или переменными), то все идет не так, но если они выполняются в разных процессах, обе они в порядке. В машине Linux я использую

mvn -U clean  test -Dtest=path 

чтобы выполнить задачу, и потому что моя статическая переменная - это запуск контейнера (или, может быть, вы инициализируете новый загрузчик классов), поэтому он останется до остановки jvm, а jvm остановится только после остановки всех задач в одном процессе. Каждое задание запускает новый контейнер (или загрузчик классов), и это сбивает с толку jvm. В результате происходит ошибка. Итак, как это решить? Мое решение состоит в том, чтобы добавить новую команду в команду maven и заставить каждую задачу помещаться в один и тот же контейнер.

-Dxxx.version=xxxxx #sorry can't post more

Возможно, вы уже решили эту проблему, но все же надеетесь, что это поможет другим, кто столкнется с той же проблемой.


Более того, когда код выполняется на компьютере с Linux, следуйте приведенной выше ошибке, возникает еще одна проблема: java.lang.ExceptionInInitializerError: nullэто означает, что не может найти класс в загрузчике классов или не знаю, какой из них загрузить (я полагаю). Вы встречали это?
— MonkeyKing

1

У меня было то же исключение - но только во время работы в режиме отладки, именно так я решил проблему (через 3 полных дня): в build.gradle у меня было: "multiDexEnabled true", установленный в разделе defaultConfig.

        defaultConfig {
    applicationId "com.xxx.yyy"
    minSdkVersion 15
    targetSdkVersion 28
    versionCode 5123
    versionName "5123"
    // Enabling multidex support.
    multiDexEnabled true
}

но, видимо, этого было недостаточно. но когда я изменился:

public class MyAppClass  extends Application 

чтобы:

public class MyAppClass  extends MultiDexApplication 

это решило это. надеюсь, это поможет кому-то


0

Если вы работаете над проектом Android, убедитесь, что вы не вызываете статические методы ни для каких классов Android. Я использую только JUnit + Mockito, так что, может быть, некоторые другие фреймворки могут помочь вам вообще избежать этой проблемы, я не уверен.

Моя проблема была вызвана Uri.parse(uriString)как часть статического инициализатора для модульного теста. Класс Uri - это Android API, поэтому сборка тестового модуля не смогла его найти. nullВместо этого я изменил это значение, и все вернулось к норме.


0

У меня были те же проблемы: java.lang.NoClassDefFoundError: Не удалось инициализировать класс com.xxx.HttpUtils

static {
    //code for loading properties from file
}

это проблема среды. Это означает, что свойства в application.yml неверны или пусты!


0

Я сталкиваюсь с той же проблемой. Я добавил объект bean в статический блок, как показано ниже:

static {
    try{
        mqttConfiguration = SpringBootBeanUtils.<MqttConfiguration>getBean(MqttConfiguration.class);
    }catch (Throwable e){
        System.out.println(e);
    }
 }

Просто потому, что процесс, инициированный моим объектом bean, вызвал NPE, у меня возникли проблемы с этим. Поэтому я думаю, что вы должны тщательно проверить статический блок кода.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.