it-swarm.com.ru

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

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

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

143
Leon

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

static {
    //code for loading properties from file
}

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

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

176
John Vint

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

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

108
jeha

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

static {
  try {

    ... your init code here

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

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

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

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

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

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

Решение

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

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

3
KerenSi

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

1
TriMix

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

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

1
Elad

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

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

0
lifeson106

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

mvn -U clean  test -Dtest=path 

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

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

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

0
MonkeyKing