Почему я получаю NoClassDefFoundError в Java?

Я получаю NoClassDefFoundError когда я запускаю свое Java-приложение. Что обычно является причиной этого?

32 ответа

Решение

Это происходит, когда существует файл класса, от которого зависит ваш код, и он присутствует во время компиляции, но не найден во время выполнения. Ищите различия во времени сборки и во время выполнения классов.

Хотя возможно, что это связано с несоответствием пути к классам между временем компиляции и временем выполнения, это не всегда так.

В этом случае важно сохранить два или три разных исключения в нашей голове:

  1. java.lang.ClassNotFoundException Это исключение указывает, что класс не был найден в пути к классам. Это указывает на то, что мы пытались загрузить определение класса, а класс не существовал в пути к классам.

  2. java.lang.NoClassDefFoundError Это исключение указывает на то, что JVM искала в своей внутренней структуре данных определения класса определение класса и не нашла его. Это отличается от того, что он не может быть загружен из пути к классам. Обычно это указывает на то, что мы ранее пытались загрузить класс из пути к классам, но по какой-то причине это не удалось - теперь мы пытаемся использовать класс снова (и, следовательно, нужно загрузить его, так как в прошлый раз он не удался), но мы ' Мы даже не собираемся пытаться загрузить его, потому что мы не смогли загрузить его раньше (и разумно подозреваем, что у нас снова будет ошибка). Более ранний сбой мог быть ClassNotFoundException или ExceptionInInitializerError (указывающий на сбой в блоке статической инициализации) или любым другим количеством проблем. Дело в том, что NoClassDefFoundError не обязательно является проблемой пути к классам.

Вот код для иллюстрации java.lang.NoClassDefFoundError, Пожалуйста, смотрите ответ Джареда для подробного объяснения.

NoClassDefFoundErrorDemo.java

public class NoClassDefFoundErrorDemo {
    public static void main(String[] args) {
        try {
            // The following line would throw ExceptionInInitializerError
            SimpleCalculator calculator1 = new SimpleCalculator();
        } catch (Throwable t) {
            System.out.println(t);
        }
        // The following line would cause NoClassDefFoundError
        SimpleCalculator calculator2 = new SimpleCalculator();
    }

}

SimpleCalculator.java

public class SimpleCalculator {
    static int undefined = 1 / 0;
}

NoClassDefFoundError в Java

Определение:

  1. Виртуальная машина Java не может найти определенный класс во время выполнения, который был доступен во время компиляции.

  2. Если класс присутствовал во время компиляции, но не был доступен в java classpath во время выполнения.

Примеры:

  1. Класс не находится в Classpath, нет точного способа узнать его, но много раз вы можете просто посмотреть, как распечатать System.getproperty("java.classpath"), и он напечатает classpath оттуда, по крайней мере, вы можете получить идея вашего фактического пути к классам во время выполнения.
  2. Простой пример NoClassDefFoundError - класс принадлежит отсутствующему файлу JAR или JAR не был добавлен в classpath, или иногда имя jar было изменено кем-то, как в моем случае один из моих коллег изменил tibco.jar на tibco_v3.jar, и программа не удалось с java.lang.NoClassDefFoundError, и мне было интересно, что не так.

  3. Просто попробуйте запустить явно -classpath с тем классом, который, по вашему мнению, будет работать, и если он работает, то это верный короткий признак того, что кто-то переопределяет java classpath.

  4. Проблема с правами доступа к файлу JAR также может вызвать NoClassDefFoundError в Java.
  5. Опечатка в конфигурации XML также может вызвать NoClassDefFoundError в Java.
  6. когда ваш скомпилированный класс, который определен в пакете, не присутствует в том же пакете во время загрузки, как в случае с JApplet, он выдаст NoClassDefFoundError в Java.

Возможные решения:

  1. Класс недоступен в Java Classpath.
  2. Если вы работаете в среде J2EE, то видимость Class среди нескольких Classloader также может вызвать java.lang.NoClassDefFoundError, подробное обсуждение см. В разделе примеров и сценариев.
  3. Проверьте наличие java.lang.ExceptionInInitializerError в файле журнала. NoClassDefFoundError из-за сбоя статической инициализации встречается довольно часто.
  4. Поскольку NoClassDefFoundError является подклассом java.lang.LinkageError, он также может появиться, если одна из его зависимостей, такая как нативная библиотека, может быть недоступна.
  5. Любой сценарий запуска переопределяет переменную среды Classpath.
  6. Возможно, вы запускаете программу с помощью команды jar, а класс не определен в атрибуте ClassPath файла манифеста.

Ресурсы:

3 способа решить NoClassDefFoundError

java.lang.NoClassDefFoundError Образцы проблем

Я обнаружил, что иногда я получаю ошибку NoClassDefFound, когда код компилируется с несовместимой версией класса, найденной во время выполнения. Конкретный экземпляр, который я помню, связан с библиотекой оси Apache. На моем пути к классам во время выполнения было 2 версии, и он выбирал устаревшую и несовместимую версию, а не правильную, вызывая ошибку NoClassDefFound. Это было в приложении командной строки, где я использовал команду, подобную этой.

set classpath=%classpath%;axis.jar

Я смог заставить его подобрать правильную версию, используя:

set classpath=axis.jar;%classpath%;

Один интересный случай, в котором вы можете увидеть много NoClassDefFoundErrors когда вы:

  1. throw RuntimeException в static блок вашего класса Example
  2. Перехватить его (или если это просто не имеет значения, как если бы он был брошен в одном тестовом примере)
  3. Попробуйте создать экземпляр этого класса Example

static class Example {
    static {
        thisThrowsRuntimeException();
    }
}

static class Simulation {

    Simulation() {
        try {
            new Example();
        } catch (Throwable ignored) { //simulating catching RuntimeException from static block

            // DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in Stackru
        }

        new Example(); //this throws NoClassDefFoundError
    }
}

NoClassDefError будет брошен в сопровождении ExceptionInInitializerError из статического блока RuntimeException,


Это особенно важно, когда вы видите NoClassDefFoundErrors в ваших единицах испытаний.

Таким образом, вы "разделяете" static выполнение блока между тестами, но начальное ExceptionInInitializerError будет только в одном тестовом случае. Первый, который использует проблемные Example учебный класс. Другие тестовые случаи, которые используют Example класс просто бросит NoClassDefFoundErrors,

Это лучшее решение, которое я нашел до сих пор.

Предположим, у нас есть пакет с именем org.mypackage содержащий классы:

  • HelloWorld (основной класс)
  • SupportClass
  • UtilClass

и файлы, определяющие этот пакет, физически хранятся в каталоге D:\myprogram (в Windows) или /home/user/myprogram (в Linux).

Структура файла будет выглядеть так:

Когда мы вызываем Java, мы указываем имя приложения для запуска: org.mypackage.HelloWorld, Однако мы также должны указать Java, где искать файлы и каталоги, определяющие наш пакет. Итак, чтобы запустить программу, мы должны использовать следующую команду:

Я использовал Spring Framework с Maven и решил эту ошибку в своем проекте.

В классе произошла ошибка во время выполнения. Я читал свойство как целое число, но когда оно прочитало значение из файла свойств, его значение было двойным.

Spring не дал мне полной трассировки стека о том, на какой линии произошла ошибка во время выполнения. Просто сказано NoClassDefFoundError, Но когда я выполнил его как нативное Java-приложение (взяв его из MVC), он дал ExceptionInInitializerError которая была истинной причиной и которая, как я проследил ошибку.

Ответ @xli дал мне понимание того, что может быть не так в моем коде.

Я получаю NoClassFoundError, когда классы, загруженные загрузчиком классов времени выполнения, не могут получить доступ к классам, уже загруженным загрузчиком Java. Поскольку разные загрузчики классов находятся в разных доменах безопасности (в соответствии с java), jvm не позволит разрешать классы, уже загруженные корневым загрузчиком, в адресном пространстве загрузчика времени выполнения.

Запустите вашу программу с помощью "java -javaagent:tracer.jar [ВАШИ java ARGS]"

Он производит вывод, показывающий загруженный класс, и загрузчик env, который загрузил класс. Очень полезно отслеживать, почему класс не может быть решен.

// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5

import java.lang.instrument.*;
import java.security.*;

// manifest.mf
// Premain-Class: ClassLoadTracer

// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class

// java -javaagent:tracer.jar  [...]

public class ClassLoadTracer 
{
    public static void premain(String agentArgs, Instrumentation inst) 
    {
        final java.io.PrintStream out = System.out;
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

                String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
                out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);

                // dump stack trace of the thread loading class 
                Thread.dumpStack();

                // we just want the original .class bytes to be loaded!
                // we are not instrumenting it...
                return null;
            }
        });
    }
}

Методика ниже помогла мне много раз:

System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

где TheNoDefFoundClass - это класс, который может быть "потерян" из-за предпочтения более старой версии той же библиотеки, что и ваша программа. Чаще всего это происходит в тех случаях, когда клиентское программное обеспечение развертывается в доминирующем контейнере, оснащенном собственными загрузчиками классов и множеством древних версий наиболее популярных библиотек.

ClassNotFoundException против NoClassDefFoundError

[ClassLoader]

Статическая и динамическая загрузка классов

Static(Implicit) class loading - результат ссылки, создания экземпляра или наследования.

      MyClass myClass = new MyClass();

Dynamic(Explicit) class loading является результатом Class.forName(), loadClass(), findSystemClass()

      MyClass myClass = (MyClass) Class.forName("MyClass").newInstance();

В каждом классе есть ClassLoader который использует loadClass(String name); поэтому

      explicit class loader uses implicit class loader

NoClassDefFoundError является частью explicit class loader. это Error чтобы гарантировать, что при компиляции этот класс присутствовал, но сейчас (в то время) его нет

ClassNotFoundException является частью implicit class loader. это Exception быть эластичным со сценариями, в которых его можно использовать дополнительно - например, отражение.

В случае, если вы сгенерировали код (EMF и т. Д.), Может быть слишком много статических инициализаторов, которые занимают все пространство стека.

См. Вопрос переполнения стека. Как увеличить размер стека Java?,

В моем случае я получал эту ошибку из-за несоответствия версий JDK. Когда я пытался запустить приложение из Intelij, оно не работало, но затем запуск из командной строки работал. Это связано с тем, что Intelij пытался запустить его с установленным Java 11 JDK, но в командной строке он работал с Java 8 JDK. После переключения этого параметра в меню "Файл"> "Структура проекта"> "Настройки проекта"> "SDK проекта" у меня все заработало.

Я исправил свою проблему, отключив preDexLibraries для всех модулей:

dexOptions {
        preDexLibraries false
        ...

Я получил эту ошибку, когда добавил в свой проект зависимость Maven другого модуля, проблема была наконец решена путем добавления -Xss2mк опции JVM моей программы (с JDK5.0 по умолчанию это один мегабайт). Считается, что у программы недостаточно стека для загрузки класса.

Обновите [https://www.infoq.com/articles/single-file-execution-java11/]:

В Java SE 11 вы можете запускать отдельный файл исходного кода напрямую, без промежуточной компиляции. Просто для вашего удобства, чтобы новичкам вроде вас не приходилось запускать javac + java (конечно, оставляя их в недоумении, почему это так).

NoClassDefFoundError Это также может произойти, если какой-либо ресурс недоступен во время выполнения, например, файл свойств, который уязвимый класс пытается загрузить из META-INF каталог. Если не поймаешь NoClassDefFoundErrorиногда вы не сможете увидеть полную трассировку стека; чтобы преодолеть это, вы можете временно использовать catch пункт для Throwable:

try {
    // Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
    Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}

Две разные кассовые копии одного и того же проекта

В моем случае проблема заключалась в неспособности Eclipse различать две разные копии одного и того же проекта. У меня один заблокирован на транке (контроль версий SVN), а другой работает в одной ветви одновременно. Я опробовал одно изменение в рабочей копии как тестовый пример JUnit, который включал в себя извлечение частного внутреннего класса в открытый класс самостоятельно, и пока он работал, я открываю другую копию проекта, чтобы посмотреть на некоторые другие часть кода, которая нуждалась в изменениях. В какой-то момент NoClassDefFoundError выскочил с жалобой на то, что частного внутреннего класса там не было; двойной щелчок в трассировке стека привел меня к исходному файлу в неправильной копии проекта.

Закрытие транковой копии проекта и запуск тестового примера снова избавили от проблемы.

Я получал NoClassDefFoundError при попытке развернуть приложение на серверах Tomcat / JBOSS. Я играл с разными зависимостями, чтобы решить проблему, но получал ту же ошибку. Отмечены все зависимости javax.*, Как указано в pom.xml, и война буквально не имеет в нем зависимости. Тем не менее проблема продолжала появляться.

Наконец понял, что в src / main / webapps / WEB-INF / classes была папка классов, которая копировалась в мою войну, поэтому вместо скомпилированных классов эти классы копировались, поэтому никакое изменение зависимости не решало проблему.

Следовательно, будьте осторожны, если какие-либо ранее скомпилированные данные копируются. После удаления папки классов и новой компиляции это сработало! ..

У меня возникла интересная проблема с NoClassDefFoundError в JavaEE, работающем с сервером Liberty. Я использовал адаптеры ресурсов IMS, а в моем server.xml уже был адаптер ресурсов для imsudbJXA.rar. Когда я добавлял новый адаптер для imsudbXA.rar, я начинал получать эту ошибку для объектов экземпляра для DLIException, IMSConnectionSpec или SQLInteractionSpec. Я не мог понять, почему, но решил это, создав новый server.xml для моей работы, используя только imsudbXA.rar. Я уверен, что использование нескольких адаптеров ресурсов в server.xml - это нормально, у меня просто не было времени разбираться в этом.

У меня была эта ошибка, но я не мог найти решение на основе этой темы, но решил ее сам.

Для моей проблемы я компилировал этот код:

package valentines;

import java.math.BigInteger;
import java.util.ArrayList;

public class StudentSolver {
    public static ArrayList<Boolean> solve(ArrayList<ArrayList<BigInteger>> problems) {
        //DOING WORK HERE
        
    }
    public static void main(String[] args){
        //TESTING SOLVE FUNCTION
    }
    
}

Затем я компилировал этот код в структуру папок, которая была похожа на /ProjectName/valentines. Компиляция работала нормально, но пыталась выполнить: java StudentSolver

Я получал NoClassDefError.

Чтобы исправить это, я просто удалил: package valentines;

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

Если кто-то приходит сюда из-за java.lang.NoClassDefFoundError: org/apache/log4j/Logger ошибка, в моем случае это было вызвано тем, что я использовал log4j 2 (но я не добавил все файлы, которые идут с ним), а некоторая библиотека зависимостей использовала log4j 1. Решением было добавить мост Log4j 1.x: яс log4j-1.2-api-<version>.jar который идет с log4j 2. Больше информации в log4j 2 миграции.

Это также может быть связано с тем, что вы копируете файл кода из IDE с определенным именем пакета и хотите попробовать запустить его с помощью терминала. Сначала вам придется удалить имя пакета из кода. Это происходит со мной.

Мое решение состояло в том, чтобы «воспользоваться» содержимым пути к классам для конкретных отсутствующих классов. В моем случае у меня было 2 зависимости, и хотя я смог успешно скомпилировать с помощью javac..., я не смог запустить полученный файл класса с помощью java..., потому что динамический класс в банке BouncyCastle не мог быть загружается во время выполнения.

      javac --classpath "ext/commons-io-2.11.0;ext/bc-fips-1.0.2.3" hello.java

Таким образом, во время компиляции и во время выполнения JVM знает, где получить зависимости Apache Commons и BouncyCastle, однако при запуске этого я получил

      Error: Unable to initialize main class hello
Caused by: java.lang.NoClassDefFoundError: 
org/bouncycastle/jcajce/provider/BouncyCastleFipsProvider

Поэтому я вручную создал новую папку с именем ext в том же месте в соответствии с путем к классам, куда я затем поместил банку BouncyCastle, чтобы убедиться, что она будет найдена во время выполнения. Вы можете поместить банку относительно файла класса или файла jar, если в результирующем манифесте указано местоположение банки. Примечание. Мне нужно использовать только одну банку, содержащую отсутствующий файл класса.

Эта ошибка может быть вызвана непроверенными требованиями к версии Java.

В моем случае мне удалось устранить эту ошибку при создании громкого проекта с открытым исходным кодом, переключившись с Java 9 на Java 8 с помощью SDKMAN!,

sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu

Затем выполните чистую установку, как описано ниже.


При использовании Maven в качестве инструмента сборки иногда полезно - и, как правило, приятно, делать чистую "установку" сборки с отключенным тестированием.

mvn clean install -DskipTests

Теперь, когда все собрано и установлено, вы можете продолжить и запустить тесты.

mvn test

Для меня проблема была связана с неправильными зависимостями, добавленными в pom . Чтобы проверить, ваша ли это проблема, запуститеmvn clean verifyи он должен это отметить.

Я получил ошибки NoClassDefFound, когда не экспортировал класс на вкладке "Порядок и экспорт" в пути сборки Java моего проекта. Обязательно поставьте галочку на вкладке "Заказ и экспорт" всех зависимостей, которые вы добавляете в путь сборки проекта. См. Предупреждение Eclipse: XXXXXXXXXXX.jar не будет экспортирован или опубликован. Runtime ClassNotFoundExceptions может привести.

Здесь все говорят о некоторых вещах конфигурации Java, проблемах JVM и т. Д., В моем случае ошибка вообще не была связана с этими темами и имела очень тривиальную и легко решаемую причину: у меня была неправильная аннотация на моей конечной точке в моем контроллере (Приложение Spring Boot).

У меня была такая же проблема, и я был на складе много часов.

Я нашел решение. В моем случае из-за этого был определен статический метод. JVM не может создать другой объект этого класса.

Например,

private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");

Java не смог найти класс A во время выполнения. Класс А был в Maven проекте ArtClient из другого рабочего пространства. Поэтому я импортировал ArtClient в свой проект Eclipse. Два моих проекта использовали ArtClient в качестве зависимости. Я изменил ссылку на библиотеку на ссылку проекта для этих (Build Path -> Configure Build Path).

И проблема ушла.

Другие вопросы по тегам