Otrzymuję komunikat o NoClassDefFoundError
uruchomieniu aplikacji Java. Co zazwyczaj jest tego przyczyną?
Otrzymuję komunikat o NoClassDefFoundError
uruchomieniu aplikacji Java. Co zazwyczaj jest tego przyczyną?
Odpowiedzi:
Jest to spowodowane, gdy istnieje plik klasy, od którego zależy Twój kod, i jest on obecny w czasie kompilacji, ale nie można go znaleźć w czasie wykonywania. Sprawdź różnice w czasie kompilacji i ścieżkach klas środowiska wykonawczego.
Chociaż możliwe jest, że jest to spowodowane niedopasowaniem ścieżki klasowej między czasem kompilacji a czasem wykonywania, niekoniecznie jest to prawda.
W tym przypadku ważne jest zachowanie dwóch lub trzech różnych wyjątków:
java.lang.ClassNotFoundException
Ten wyjątek wskazuje, że klasa nie została znaleziona w ścieżce klasy. Oznacza to, że próbowaliśmy załadować definicję klasy, a klasa nie istniała w ścieżce klasy.
java.lang.NoClassDefFoundError
Ten wyjątek wskazuje, że JVM szukał definicji swojej klasy w wewnętrznej strukturze danych definicji klasy i jej nie znalazł. Jest to inne niż stwierdzenie, że nie można go załadować ze ścieżki klas. Zwykle oznacza to, że poprzednio próbowaliśmy załadować klasę ze ścieżki klas, ale z jakiegoś powodu nie udało się - teraz próbujemy ponownie użyć tej klasy (i dlatego musimy ją załadować, ponieważ poprzednio nie powiodła się), ale „ nawet nie będziemy próbować go załadować, ponieważ nie udało nam się go wcześniej załadować (i mamy uzasadnione podejrzenia, że znowu się nie powiedziemy). Wcześniejszym niepowodzeniem może być ClassNotFoundException lub ExceptionInInitializerError (wskazujący błąd w bloku statycznej inicjalizacji) lub dowolną liczbę innych problemów. Chodzi o to, że NoClassDefFoundError niekoniecznie jest problemem ścieżki klasowej.
Error: Could not find or load main class
, zostanie zaklasyfikowany do jakiej kategorii błędu?
Oto kod do zilustrowania java.lang.NoClassDefFoundError
. Zobacz odpowiedź Jareda do szczegółowego wyjaśnienia.
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;
}
SimpleCalculator
po podzieleniu przez zero? Czy ktoś ma odniesienie do oficjalnej dokumentacji tego zachowania?
new SimpleCalculator()
wywołaniu pojawia się wyjątek ExceptionInInitializerError spowodowany wyjątkiem ArithmeticException. Przy drugim wywołaniu new SimpleCalculator()
otrzymasz NoClassDefFoundError tak czysty jak każdy inny. Chodzi o to, że możesz uzyskać NoClassDefFoundError z innego powodu niż SimpleCalculator.class, który nie znajduje się w ścieżce klas w czasie wykonywania.
NoClassDefFoundError W Javie
Definicja:
Java Virtual Machine nie jest w stanie znaleźć konkretnej klasy w czasie wykonywania, która była dostępna w czasie kompilacji.
Jeśli klasa była obecna w czasie kompilacji, ale nie była dostępna w ścieżce klas Java w czasie wykonywania.
Przykłady:
Prostym przykładem NoClassDefFoundError jest to, że klasa należy do brakującego pliku JAR lub JAR nie został dodany do ścieżki klasy lub czasami nazwa jar została zmieniona przez kogoś takiego jak w moim przypadku jeden z moich kolegów zmienił tibco.jar na tibco_v3.jar, a program jest błąd z java.lang.NoClassDefFoundError i zastanawiałem się, co jest nie tak.
Po prostu spróbuj uruchomić z jawnie opcją -classpath ze ścieżką klasy, która Twoim zdaniem będzie działać, a jeśli działa, to jest to pewnie krótki znak, że ktoś przesłonił ścieżkę klasy Java.
Możliwe rozwiązania:
Zasoby:
Odkryłem, że czasami pojawia się błąd NoClassDefFound, gdy kod jest kompilowany z niekompatybilną wersją klasy znalezioną w czasie wykonywania. Konkretne wystąpienie, które pamiętam, dotyczy biblioteki osi apache. W mojej ścieżce klas środowiska wykonawczego były w rzeczywistości 2 wersje, które pobierały nieaktualną i niekompatybilną wersję, a nie poprawną, powodując błąd NoClassDefFound. To było w aplikacji wiersza poleceń, w której korzystałem z polecenia podobnego do tego.
set classpath=%classpath%;axis.jar
Byłem w stanie uzyskać odpowiednią wersję, używając:
set classpath=axis.jar;%classpath%;
To najlepsze rozwiązanie jakie do tej pory znalazłem.
Załóżmy, że mamy pakiet o nazwie org.mypackage
zawierający klasy:
a pliki definiujące ten pakiet są przechowywane fizycznie w katalogu D:\myprogram
(w systemie Windows) lub/home/user/myprogram
(w systemie Linux).
Struktura pliku będzie wyglądać następująco:
Kiedy wzywamy Java, możemy określić nazwę aplikacji do uruchomienia: org.mypackage.HelloWorld
. Musimy jednak powiedzieć Javie, gdzie szukać plików i katalogów definiujących nasz pakiet. Aby uruchomić program, musimy użyć następującego polecenia:
Korzystałem z Spring Framework z Maven i rozwiązałem ten błąd w moim projekcie.
W klasie wystąpił błąd czasu wykonywania. Czytałem właściwość jako liczbę całkowitą, ale kiedy odczytała wartość z pliku właściwości, jej wartość była podwójna.
Wiosna nie dała mi pełnego śladu stosu, w której linii wystąpił błąd środowiska wykonawczego. Po prostu powiedział NoClassDefFoundError
. Ale kiedy wykonałem go jako natywną aplikację Java (biorąc go z MVC), dałemExceptionInInitializerError
która była prawdziwa przyczyna i w jaki sposób wyśledziłem błąd.
Odpowiedź @ xli dała mi wgląd w to, co może być źle w moim kodzie.
NoClassDefFoundError
tak naprawdę było spowodowane przez ExceptionInInitalizerError
, co było spowodowane przez DateTimeParseException
). To trochę mylące, prawda? Wiem, że prawdopodobnie mieli ku temu powody, ale tak miło byłoby mieć chociaż małą podpowiedź, która NoClassDefFoundError
była wynikiem innego wyjątku, bez potrzeby wnioskowania. ExceptionInInitializerError
Ponowne rzucenie byłoby znacznie wyraźniejsze. Czasami związek między nimi może nie być tak oczywisty.
Dostaję NoClassFoundError, gdy klasy ładowane przez moduł ładujący środowiska wykonawczego nie mogą uzyskać dostępu do klas już załadowanych przez program ładujący root Java. Ponieważ różne moduły ładujące znajdują się w różnych domenach bezpieczeństwa (zgodnie z Javą), Jvm nie pozwoli na rozpoznanie klas już załadowanych przez program ładujący root w przestrzeni adresowej modułu ładującego środowisko wykonawcze.
Uruchom swój program z „java -javaagent: tracer.jar [YOUR java ARGS]”
Generuje dane wyjściowe pokazujące załadowaną klasę i środowisko env loadera, które załadowało klasę. Bardzo pomocne jest śledzenie, dlaczego nie można rozwiązać klasy.
// 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;
}
});
}
}
Ciekawym przypadkiem, w którym możesz wiele zobaczyć, NoClassDefFoundErrors
jest:
throw
RuntimeException
w static
bloku klasyExample
Example
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
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 StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError
zostanie wyrzucony w towarzystwie z ExceptionInInitializerError
bloku statycznego RuntimeException
.
Jest to szczególnie ważny przypadek, gdy widzisz NoClassDefFoundErrors
w TESTACH JEDNOSTKI .
W pewien sposób „udostępniasz” static
wykonanie bloku między testami, ale początkowa ExceptionInInitializerError
będzie tylko w jednym przypadku testowym. Pierwszy, który korzysta z problematycznej Example
klasy. Inne przypadki testowe korzystające z tej Example
klasy po prostu rzucą NoClassDefFoundErrors
.
Poniższa technika pomogła mi wiele razy:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
gdzie TheNoDefFoundClass to klasa, która może zostać „utracona” z powodu preferencji dla starszej wersji tej samej biblioteki używanej przez twój program. Zdarza się to najczęściej w przypadkach, gdy oprogramowanie klienckie jest wdrażane w dominującym kontenerze, uzbrojonym we własne moduły ładujące klasy i mnóstwo starożytnych wersji najpopularniejszych bibliotek.
W przypadku wygenerowania kodu (EMF itp.) Może być zbyt wiele statycznych inicjatorów, które zajmują całe miejsce na stosie.
Zobacz pytanie Przepełnienie stosu Jak zwiększyć rozmiar stosu Java? .
NoClassDefFoundError
może również wystąpić, gdy inicjator statyczny próbuje załadować pakiet zasobów, który nie jest dostępny w środowisku wykonawczym, na przykład plik właściwości, który klasa, której dotyczy problem, próbuje załadować z META-INF
katalogu, ale go nie ma. Jeśli nie złapiesz NoClassDefFoundError
, czasami nie będziesz w stanie zobaczyć pełnego śladu stosu; Aby temu zaradzić, możesz tymczasowo użyć catch
klauzuli, aby 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);
}
for example a properties file that the affected class tries to load from the META-INF directory
. Tak się właściwie stało i udało mi się rozwiązać NoClassDefFoundError
, dodając brakujący plik właściwości. Dodałem tę odpowiedź właśnie dlatego, że nie można oczekiwać tego błędu w wyżej wymienionych okolicznościach.
static
inicjalizacji ... co spowodowało niesprawdzony wyjątek i spowodowało inicjację nie zdać. Zrobiłby to każdy niesprawdzony wyjątek propagowany z inicjalizacji statycznej.
static
inicjalizacji), chciałbym zobaczyć rzeczywisty przykład (np. MCVE), który demonstruje zachowanie.
Wystąpił ten błąd, gdy dodałem zależność Maven od innego modułu do mojego projektu, problem został w końcu rozwiązany przez dodanie -Xss2m
do opcji JVM mojego programu (domyślnie jest to jeden megabajt od JDK5.0). Uważa się, że program nie ma wystarczającego stosu, aby załadować klasę.
Jeśli ktoś tu przychodzi z powodu java.lang.NoClassDefFoundError: org/apache/log4j/Logger
błędu, w moim przypadku został on utworzony, ponieważ użyłem log4j 2 (ale nie dodałem wszystkich plików, które są z nim związane), a niektóre biblioteki zależności wykorzystały log4j 1. Rozwiązaniem było dodanie Log4j Most 1.x: słoik log4j-1.2-api-<version>.jar
dostarczany z log4j 2. Więcej informacji na temat migracji log4j 2 .
W moim przypadku problemem była niezdolność Eclipse do rozróżnienia dwóch różnych kopii tego samego projektu. Mam jeden zablokowany na pniu (kontrola wersji SVN), a drugi pracuje w jednej gałęzi na raz. Wypróbowałem jedną zmianę w kopii roboczej jako przypadek testowy JUnit, która obejmowała wyodrębnienie prywatnej klasy wewnętrznej, aby sama była klasą publiczną i podczas gdy działała, otwieram drugą kopię projektu, aby rozejrzeć się po innej część kodu, która wymagała zmian. W pewnym momencieNoClassDefFoundError
wyskoczyli narzekając, że nie ma prywatnej klasy wewnętrznej; dwukrotne kliknięcie śledzenia stosu doprowadziło mnie do pliku źródłowego w niewłaściwej kopii projektu.
Zamknięcie kopii projektu i ponowne uruchomienie skrzynki testowej pozbyło się problemu.
Ten błąd może być spowodowany niesprawdzonymi wymaganiami dotyczącymi wersji Java .
W moim przypadku udało mi się rozwiązać ten błąd, budując głośny projekt open source, przechodząc z Java 9 na Java 8 za pomocą SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Następnie wykonaj czystą instalację, jak opisano poniżej.
Kiedy używasz Maven jako narzędzia do kompilacji, czasem pomocne jest - i zwykle satysfakcjonujące - wykonanie czystej kompilacji „instaluj” z wyłączonym testowaniem .
mvn clean install -DskipTests
Teraz, gdy wszystko zostało zbudowane i zainstalowane, możesz przejść testy i przeprowadzić je.
mvn test
Wystąpiły błędy NoClassDefFound, gdy nie wyeksportowałem klasy na karcie „Zamów i eksportuj” na ścieżce kompilacji Java mojego projektu. Pamiętaj, aby zaznaczyć znacznik wyboru na karcie „Zamów i eksportuj” wszystkich zależności dodanych do ścieżki kompilacji projektu. Zobacz ostrzeżenie Eclipse: XXXXXXXXXXX.jar nie zostanie wyeksportowany ani opublikowany. Może to spowodować wyjątki Runtime ClassNotFoundExceptions .
W moim przypadku występował ten błąd z powodu niedopasowania w wersjach JDK. Kiedy próbowałem uruchomić aplikację z Intelij, to nie działało, ale działało z wiersza poleceń. Wynika to z faktu, że Intelij próbował uruchomić go z zainstalowanym pakietem JDK Java 11, ale w wierszu komend uruchomiono go z pakietem JDK Java 8. Po zmianie tego ustawienia w Plik> Struktura projektu> Ustawienia projektu> Zestaw SDK projektu, zadziałało to dla mnie.
Wszyscy mówią tutaj o niektórych kwestiach związanych z konfiguracją Java, problemami z JVM itp. W moim przypadku błąd nie był w ogóle związany z tymi tematami i miał bardzo trywialny i łatwy do rozwiązania powód: miałem niepoprawną adnotację w punkcie końcowym w moim kontrolerze ( Aplikacja Spring Boot).
Miałem interesujący problem z NoClassDefFoundError w JavaEE współpracującym z serwerem Liberty. Korzystałem z adapterów zasobów IMS, a mój plik server.xml miał już adapter zasobów dla imsudbJXA.rar. Kiedy dodałem nowy adapter do imsudbXA.rar, zacząłem otrzymywać ten błąd na przykład dla obiektów DLIException, IMSConnectionSpec lub SQLInteractionSpec. Nie mogłem zrozumieć, dlaczego, ale rozwiązałem ten problem, tworząc nowy server.xml do mojej pracy, używając tylko imsudbXA.rar. Jestem pewien, że używanie wielu adapterów zasobów w pliku server.xml jest w porządku, po prostu nie miałem czasu, aby się tym zająć.
Java nie mogła znaleźć klasy A w środowisku wykonawczym. Klasa A była w projekcie maven ArtClient z innego obszaru roboczego. Zaimportowałem więc ArtClient do mojego projektu Eclipse. Dwa moje projekty wykorzystywały ArtClient jako zależność. Zmieniłem odwołanie do biblioteki na odwołanie do projektu dla tych (Ścieżka kompilacji -> Konfiguruj ścieżkę kompilacji).
Problem zniknął.
Miałem ten sam problem i miałem zapas na wiele godzin.
Znalazłem rozwiązanie. W moim przypadku zdefiniowano z tego powodu metodę statyczną. JVM nie może utworzyć kolejnego obiektu tej klasy.
Na przykład,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Otrzymałem ten komunikat po usunięciu dwóch plików z biblioteki SRC, a kiedy je przywróciłem, nadal widziałem ten komunikat o błędzie.
Moje rozwiązanie brzmiało: Uruchom ponownie Eclipse. Od tego czasu nie widziałem tego komunikatu ponownie :-)
Upewnij się, że mecze w module:app
i module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
i dwa }
). Czy możesz to naprawić?