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 відсутній у класі.

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

Btw: код працює на моїй локальній машині. Але не вдалося працювати, коли я розгортаю його з деяким сценарієм на сервері Linux. Тому я думаю, що це не проблема коду. Але чомусь. процес розгортання дуже важко відстежити.

У чому може бути проблема?


Чи відповідна структура каталогу у вашій банку відповідає класовому пакету?
Джон Б

потрібно бачити якесь джерело, багато речей можуть спричинити це. наприклад, заява "пакет", але файл фактично не знаходиться у відповідному шляху
jcomeau_ictx

3
Одна причина є винятком під час ініціалізації - чи є якісь інші помилки?
Майкл Брюер-Девіс

Відповіді:


211

Моя найкраща ставка, що тут є проблема:

static {
    //code for loading properties from file
}

Здавалося б, виникла якась незрозуміла ситуація і поширюється до фактичного ClassLoader, який намагається завантажити клас. Для підтвердження цього нам знадобиться стек-трек.

Або це, або це сталося під час створення PropHolder.propстатичної змінної.


Я стикаюся з тією ж проблемою раз і знову. Я впевнений, що це через staticпроблему. Що потрібно зробити, щоб вирішити проблему?
гадюка

1
Вам потрібно буде визначити, який виняток викидається з staticблоку. Для налагодження слід поставити try/catch(Exception e)навколо всього блоку і записати виняток. Вам доведеться виправити це виключення. Як правило, виняток буде зареєстровано, але його може бути важко знайти, оскільки він реєструється під час завантаження класів, що може статися дуже рано
Джон Vint

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

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

Було б легше відстежувати, якби Java видала помилку CouldNotInitializeStaticPartOfClassError або щось таке. Тоді ми як розробник знали, де шукати.
Маартен

126

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

Помістіть спробу / ловити всередині статичного ініціалізатора і подивіться на виняток. Якщо ви читаєте там деякі файли, і вони відрізняються від місцевого оточення, це дуже ймовірно, що причина проблеми (можливо, файл неможливо знайти, немає дозволів тощо).


1
одне уточнення полягає в тому, що, хоча NoClassDefFoundError не передбачає ClassNotFoundException, він все ще є можливою причиною NoClassDefFoundError.
Джон Вінт

1
Буф, якби у вас був ClassNotFoundException, тоді ClassLoader ніколи не міг би спробувати завантажити клас, правда?
jeha

4
Клас може завантажувати інший клас, який не знайдено. Причиною в цьому випадку є все ще ClassNotFoundException
John Vint

1
Я повинен був уточнити, я мав на увазі виключення.getCause ()
Джон Vint

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. Клас "Джуніт" (і тест), який розширив ще один клас.

  2. ApplicationContext ініціалізований за допомогою весни, яка запускає проект.

  3. Контекст програми було ініціалізовано методом @Before

Рішення:

Запустіть контекст програми з методу @BeforeClass, оскільки батьківський клас також вимагав деяких класів, які були ініціалізовані з контексту програми.

Сподіваюсь, це допоможе.


2

Як було сказано вище, це може бути ряд речей. У моєму випадку у мене була статично ініціалізована змінна, яка спиралася на відсутній запис у моєму файлі властивостей. Доданий файл у файл властивостей відсутній, і проблема була вирішена.


1

Всього кілька днів тому я зустрів таке саме питання, як і ваше. Весь код працює добре на моїй локальній машині, але виявляється помилка (noclassdeffound & ініціалізувати). Тож я розміщую своє рішення, але не знаю чому, я просто просуваю можливість. Сподіваюся, хтось знає, що це пояснить. @ John Vint По-перше, я покажу вам свою проблему. Мій код має статичну змінну і статичний блок. Коли я вперше зіткнувся з цією проблемою, я спробував рішення Джона Вінта і спробував зловити виняток. Однак я нічого не зловив. Тому я подумав, що це тому, що статична змінна (але тепер я знаю, що вони однакові) і все одно нічого не знайшла. Отже, я намагаюся знайти різницю між машиною 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

Я стикаюся з тією ж проблемою. Я запросив об'єкт квасолі в статичний блок, як показано нижче:

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

Тільки тому, що процес, який мій предмет бобових предметів викликав NPE, у мене виникають проблеми. Тому я думаю, ви повинні уважно перевірити ваш блок статичного коду.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.