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, поскольку родительскому классу также требуются некоторые классы, которые были инициализированы из контекста приложения.

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

KerenSi
источник
2

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

TRIMIX
источник
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 

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

Elad
источник
0

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

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

lifeson106
источник
0

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

static {
    //code for loading properties from file
}

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

user8503957
источник
0

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

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

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

лай нянь
источник