Почему я получаю NoClassDefFoundError в Java?
Я получаю NoClassDefFoundError
когда я запускаю свое Java-приложение. Что обычно является причиной этого?
32 ответа
Это происходит, когда существует файл класса, от которого зависит ваш код, и он присутствует во время компиляции, но не найден во время выполнения. Ищите различия во времени сборки и во время выполнения классов.
Хотя возможно, что это связано с несоответствием пути к классам между временем компиляции и временем выполнения, это не всегда так.
В этом случае важно сохранить два или три разных исключения в нашей голове:
java.lang.ClassNotFoundException
Это исключение указывает, что класс не был найден в пути к классам. Это указывает на то, что мы пытались загрузить определение класса, а класс не существовал в пути к классам.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
Определение:
Виртуальная машина Java не может найти определенный класс во время выполнения, который был доступен во время компиляции.
Если класс присутствовал во время компиляции, но не был доступен в java classpath во время выполнения.
Примеры:
- Класс не находится в Classpath, нет точного способа узнать его, но много раз вы можете просто посмотреть, как распечатать System.getproperty("java.classpath"), и он напечатает classpath оттуда, по крайней мере, вы можете получить идея вашего фактического пути к классам во время выполнения.
Простой пример NoClassDefFoundError - класс принадлежит отсутствующему файлу JAR или JAR не был добавлен в classpath, или иногда имя jar было изменено кем-то, как в моем случае один из моих коллег изменил tibco.jar на tibco_v3.jar, и программа не удалось с java.lang.NoClassDefFoundError, и мне было интересно, что не так.
Просто попробуйте запустить явно -classpath с тем классом, который, по вашему мнению, будет работать, и если он работает, то это верный короткий признак того, что кто-то переопределяет java classpath.
- Проблема с правами доступа к файлу JAR также может вызвать NoClassDefFoundError в Java.
- Опечатка в конфигурации XML также может вызвать NoClassDefFoundError в Java.
- когда ваш скомпилированный класс, который определен в пакете, не присутствует в том же пакете во время загрузки, как в случае с JApplet, он выдаст NoClassDefFoundError в Java.
Возможные решения:
- Класс недоступен в Java Classpath.
- Если вы работаете в среде J2EE, то видимость Class среди нескольких Classloader также может вызвать java.lang.NoClassDefFoundError, подробное обсуждение см. В разделе примеров и сценариев.
- Проверьте наличие java.lang.ExceptionInInitializerError в файле журнала. NoClassDefFoundError из-за сбоя статической инициализации встречается довольно часто.
- Поскольку NoClassDefFoundError является подклассом java.lang.LinkageError, он также может появиться, если одна из его зависимостей, такая как нативная библиотека, может быть недоступна.
- Любой сценарий запуска переопределяет переменную среды Classpath.
- Возможно, вы запускаете программу с помощью команды jar, а класс не определен в атрибуте ClassPath файла манифеста.
Ресурсы:
Я обнаружил, что иногда я получаю ошибку NoClassDefFound, когда код компилируется с несовместимой версией класса, найденной во время выполнения. Конкретный экземпляр, который я помню, связан с библиотекой оси Apache. На моем пути к классам во время выполнения было 2 версии, и он выбирал устаревшую и несовместимую версию, а не правильную, вызывая ошибку NoClassDefFound. Это было в приложении командной строки, где я использовал команду, подобную этой.
set classpath=%classpath%;axis.jar
Я смог заставить его подобрать правильную версию, используя:
set classpath=axis.jar;%classpath%;
Один интересный случай, в котором вы можете увидеть много NoClassDefFoundErrors
когда вы:
throw
RuntimeException
вstatic
блок вашего классаExample
- Перехватить его (или если это просто не имеет значения, как если бы он был брошен в одном тестовом примере)
- Попробуйте создать экземпляр этого класса
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
Статическая и динамическая загрузка классов
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).
И проблема ушла.