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.