J'obtiens un NoClassDefFoundError
lorsque j'exécute mon application Java. Quelle est généralement la cause de cela?
J'obtiens un NoClassDefFoundError
lorsque j'exécute mon application Java. Quelle est généralement la cause de cela?
Réponses:
Cela est dû au fait qu'il existe un fichier de classe dont dépend votre code et qu'il est présent au moment de la compilation mais introuvable lors de l'exécution. Recherchez les différences de temps de génération et de chemins de classe d'exécution.
Bien qu'il soit possible que cela soit dû à une incompatibilité de chemin de classe entre la compilation et l'exécution, ce n'est pas nécessairement vrai.
Il est important de garder deux ou trois exceptions différentes bien dans notre tête dans ce cas:
java.lang.ClassNotFoundException
Cette exception indique que la classe est introuvable sur le chemin de classe. Cela indique que nous essayions de charger la définition de classe et que la classe n'existait pas sur le chemin de classe.
java.lang.NoClassDefFoundError
Cette exception indique que la machine virtuelle Java a recherché dans sa structure de données de définition de classe interne la définition d'une classe et ne l'a pas trouvée. C'est différent de dire qu'il n'a pas pu être chargé à partir du chemin de classe. Habituellement, cela indique que nous avons précédemment tenté de charger une classe à partir du chemin de classe, mais cela a échoué pour une raison quelconque - maintenant, nous essayons de réutiliser la classe (et devons donc la charger, car elle a échoué la dernière fois), mais nous ' Nous n'allons même pas essayer de le charger, car nous n'avons pas pu le charger plus tôt (et nous pensons raisonnablement que nous échouerions à nouveau). L'échec précédent peut être une exception ClassNotFoundException ou ExceptionInInitializerError (indiquant une défaillance dans le bloc d'initialisation statique) ou un certain nombre d'autres problèmes. Le fait est qu'un NoClassDefFoundError n'est pas nécessairement un problème de chemin de classe.
Error: Could not find or load main class
, il sera classé dans quelle catégorie d'erreur?
Voici le code à illustrer java.lang.NoClassDefFoundError
. Veuillez voir la réponse de Jared pour une explication détaillée.
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
après la division par zéro? Quelqu'un a-t-il une référence à la documentation officielle de ce comportement?
new SimpleCalculator()
vous appelez, vous obtenez une ExceptionInInitializerError avec une cause de ArithmeticException. La deuxième fois que vous appelez, new SimpleCalculator()
vous obtenez un NoClassDefFoundError aussi pur que n'importe quel autre. Le fait est que vous pouvez obtenir un NoClassDefFoundError pour une raison autre que SimpleCalculator.class n'étant pas sur le chemin de classe au moment de l'exécution.
NoClassDefFoundError en Java
Définition:
Java Virtual Machine n'est pas en mesure de trouver une classe particulière au moment de l'exécution qui était disponible au moment de la compilation.
Si une classe était présente lors de la compilation mais n'était pas disponible dans le chemin d'accès aux classes java pendant l'exécution.
Exemples:
Un exemple simple de NoClassDefFoundError est que la classe appartient à un fichier JAR manquant ou JAR n'a pas été ajouté dans classpath ou parfois le nom du jar a été changé par quelqu'un comme dans mon cas un de mes collègues a changé tibco.jar en tibco_v3.jar et le programme est échouer avec java.lang.NoClassDefFoundError et je me demandais ce qui ne va pas.
Essayez simplement d'exécuter avec l'option -classpath explicitement avec le chemin de classe qui fonctionnera et si cela fonctionne, c'est un signe court certain que quelqu'un remplace le chemin de classe java.
Solutions possibles:
Ressources:
J'ai constaté que parfois j'obtiens une erreur NoClassDefFound lorsque le code est compilé avec une version incompatible de la classe trouvée lors de l'exécution. L'instance spécifique dont je me souviens concerne la bibliothèque d'axes Apache. Il y avait en fait 2 versions sur mon chemin de classe d'exécution et il récupérait la version obsolète et incompatible et pas la bonne, provoquant une erreur NoClassDefFound. C'était dans une application en ligne de commande où j'utilisais une commande similaire à celle-ci.
set classpath=%classpath%;axis.jar
J'ai pu l'obtenir pour récupérer la bonne version en utilisant:
set classpath=axis.jar;%classpath%;
C'est la meilleure solution j'ai trouvée jusqu'à présent.
Supposons que nous ayons un package appelé org.mypackage
contenant les classes:
et les fichiers définissant ce package sont stockés physiquement sous le répertoire D:\myprogram
(sous Windows) ou/home/user/myprogram
(sous Linux).
La structure du fichier ressemblera à ceci:
Lorsque nous invoquons Java, nous précisons le nom de l'application à exécuter: org.mypackage.HelloWorld
. Cependant, nous devons également indiquer à Java où chercher les fichiers et répertoires définissant notre package. Donc, pour lancer le programme, nous devons utiliser la commande suivante:
J'utilisais Spring Framework avec Maven et j'ai résolu cette erreur dans mon projet.
Il y avait une erreur d'exécution dans la classe. Je lisais une propriété sous forme d'entier, mais lorsqu'elle a lu la valeur du fichier de propriétés, sa valeur était double.
Spring ne m'a pas donné de trace complète de la pile sur quelle ligne le runtime a échoué. Il a simplement dit NoClassDefFoundError
. Mais quand je l'ai exécutée en tant qu'application Java native (en la retirant de MVC), cela a donné ExceptionInInitializerError
quelle était la véritable cause et comment j'ai retracé l'erreur.
La réponse de @ xli m'a donné un aperçu de ce qui peut mal se passer dans mon code.
NoClassDefFoundError
été causée par ExceptionInInitalizerError
, qui a été causée par DateTimeParseException
). C'est un peu trompeur, non? Je sais qu'ils avaient probablement leurs raisons de le faire comme ça, mais ce serait tellement agréable d'avoir au moins un petit indice, qui NoClassDefFoundError
était le résultat d'une autre exception, sans avoir besoin de le déduire. Lancer à ExceptionInInitializerError
nouveau serait beaucoup plus clair. Parfois, le lien entre les deux n'est pas si évident.
J'obtiens NoClassFoundError lorsque les classes chargées par le chargeur de classes d'exécution ne peuvent pas accéder aux classes déjà chargées par le rootloader java. Étant donné que les différents chargeurs de classe se trouvent dans différents domaines de sécurité (selon java), le jvm ne permettra pas aux classes déjà chargées par le rootloader d'être résolues dans l'espace d'adressage du chargeur d'exécution.
Exécutez votre programme avec 'java -javaagent: tracer.jar [YOUR java ARGS]'
Il produit une sortie affichant la classe chargée et le chargeur env qui a chargé la classe. Il est très utile de savoir pourquoi une classe ne peut pas être résolue.
// 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;
}
});
}
}
Un cas intéressant dans lequel vous pourriez en voir beaucoup NoClassDefFoundErrors
est lorsque vous:
throw
un RuntimeException
dans le static
bloc de votre classeExample
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
sera jeté accompagné ExceptionInInitializerError
du bloc statique RuntimeException
.
C'est un cas particulièrement important lorsque vous voyez NoClassDefFoundErrors
dans vos TESTS D'UNITÉ .
D'une certaine manière, vous "partagez" l' static
exécution du bloc entre les tests, mais l'initiale ExceptionInInitializerError
ne sera que dans un seul cas de test. Le premier qui utilise la Example
classe problématique . Les autres cas de test qui utilisent la Example
classe seront simplement lancés NoClassDefFoundErrors
.
La technique ci-dessous m'a aidé plusieurs fois:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
où TheNoDefFoundClass est la classe qui peut être "perdue" en raison d'une préférence pour une version plus ancienne de la même bibliothèque utilisée par votre programme. Cela se produit le plus souvent dans les cas où le logiciel client est déployé dans un conteneur dominant, armé de ses propres chargeurs de classe et de tonnes de versions anciennes des bibliothèques les plus populaires.
Dans le cas où vous avez généré du code (EMF, etc.), il peut y avoir trop d'initialiseurs statiques qui consomment tout l'espace de la pile.
Voir la question Stack Overflow Comment augmenter la taille de la pile Java? .
NoClassDefFoundError
peut également se produire lorsqu'un initialiseur statique tente de charger un ensemble de ressources qui n'est pas disponible au moment de l'exécution, par exemple un fichier de propriétés que la classe affectée tente de charger à partir du META-INF
répertoire, mais qui n'y est pas. Si vous n'attrapez pas NoClassDefFoundError
, parfois vous ne pourrez pas voir la trace complète de la pile; pour surmonter cela, vous pouvez temporairement utiliser une catch
clause pour 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
. Cela m'est réellement arrivé et j'ai pu résoudre le problème NoClassDefFoundError
en ajoutant le fichier de propriétés manquant. J'ai ajouté cette réponse exactement parce que l'on ne s'attendrait pas à cette erreur dans les circonstances mentionnées.
static
initialisation ... qui a déclenché une exception non vérifiée et provoqué la classe init échouer. Toute exception non vérifiée se propageant à partir de l'initialisation statique ferait cela.
static
initialisation), je serais intéressé de voir un exemple réel (c'est-à-dire un MCVE) qui illustre le comportement.
J'ai obtenu cette erreur lorsque j'ajoute la dépendance Maven d'un autre module à mon projet, le problème a finalement été résolu en ajoutant -Xss2m
à l'option JVM de mon programme (c'est un mégaoctet par défaut depuis JDK5.0). On pense que le programme n'a pas assez de pile pour charger la classe.
Si quelqu'un vient ici à cause d'une java.lang.NoClassDefFoundError: org/apache/log4j/Logger
erreur, dans mon cas, il a été produit parce que j'ai utilisé log4j 2 (mais je n'ai pas ajouté tous les fichiers qui l'accompagnent), et une bibliothèque de dépendances a utilisé log4j 1. La solution était d'ajouter le Log4j 1.x bridge: le pot log4j-1.2-api-<version>.jar
fourni avec log4j 2. Plus d'infos sur la migration log4j 2 .
Dans mon cas, le problème était l'incapacité d'Eclipse à différencier deux copies différentes du même projet. J'en ai un verrouillé sur le coffre (contrôle de version SVN) et l'autre travaillant dans une branche à la fois. J'ai essayé un changement dans la copie de travail en tant que cas de test JUnit, qui comprenait l'extraction d'une classe interne privée pour être une classe publique à part entière et pendant que cela fonctionnait, j'ouvre l'autre copie du projet pour regarder un autre partie du code qui nécessitait des modifications. À un certain point, le NoClassDefFoundError
surgi se plaignit que la classe intérieure privée n'était pas là; un double-clic dans la trace de la pile m'a amené au fichier source dans la mauvaise copie du projet.
La fermeture de la copie de tronc du projet et l'exécution à nouveau du scénario de test ont permis de résoudre le problème.
Cette erreur peut être due à des exigences de version Java non vérifiées .
Dans mon cas, j'ai pu résoudre cette erreur, tout en créant un projet open source de haut niveau, en passant de Java 9 à Java 8 à l'aide de SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Effectuez ensuite une nouvelle installation comme décrit ci-dessous.
Lorsque vous utilisez Maven comme outil de construction, il est parfois utile - et généralement gratifiant, de faire une construction «d'installation» propre avec les tests désactivés .
mvn clean install -DskipTests
Maintenant que tout a été construit et installé, vous pouvez continuer et exécuter les tests.
mvn test
J'ai reçu des erreurs NoClassDefFound lorsque je n'ai pas exporté une classe dans l'onglet "Commander et exporter" du chemin de génération Java de mon projet. Assurez-vous de mettre une coche dans l'onglet "Commander et exporter" de toutes les dépendances que vous ajoutez au chemin de génération du projet. Voir l' avertissement Eclipse: XXXXXXXXXXX.jar ne sera pas exporté ni publié. Runtime ClassNotFoundExceptions peut en résulter .
Dans mon cas, j'obtenais cette erreur en raison d'une incompatibilité dans les versions JDK. Lorsque j'ai essayé d'exécuter l'application à partir d'Intelij, cela ne fonctionnait pas, mais l'exécuter à partir de la ligne de commande a fonctionné. Cela est dû au fait qu'Intelij tentait de l'exécuter avec le JDK Java 11 qui était configuré, mais sur la ligne de commande, il s'exécutait avec le JDK Java 8. Après avoir changé ce paramètre sous Fichier> Structure du projet> Paramètres du projet> SDK du projet, cela a fonctionné pour moi.
Tout le monde parle ici de certaines choses de configuration Java, de problèmes JVM, etc., dans mon cas, l'erreur n'était pas du tout liée à ces sujets et avait une raison très triviale et facile à résoudre: j'avais une annotation erronée à mon point de terminaison dans mon contrôleur ( Application Spring Boot).
J'ai eu un problème intéressant avec NoClassDefFoundError dans JavaEE avec le serveur Liberty. J'utilisais des adaptateurs de ressources IMS et mon server.xml avait déjà un adaptateur de ressources pour imsudbJXA.rar. Lorsque j'ajoutais un nouvel adaptateur pour imsudbXA.rar, je commençais à obtenir cette erreur pour les objets d'instance pour DLIException, IMSConnectionSpec ou SQLInteractionSpec. Je ne pouvais pas comprendre pourquoi mais je l'ai résolu en créant un nouveau server.xml pour mon travail en utilisant uniquement imsudbXA.rar. Je suis sûr que l'utilisation de plusieurs adaptateurs de ressources dans server.xml est très bien, je n'ai pas eu le temps d'examiner cela.
Java n'a pas pu trouver la classe A lors de l'exécution. La classe A faisait partie du projet maven ArtClient d'un autre espace de travail. J'ai donc importé ArtClient dans mon projet Eclipse. Deux de mes projets utilisaient ArtClient comme dépendance. J'ai changé la référence de bibliothèque en référence de projet pour ceux-ci (Build Path -> Configure Build Path).
Et le problème a disparu.
J'ai eu le même problème et j'étais en stock pendant de nombreuses heures.
J'ai trouvé la solution. Dans mon cas, il y avait la méthode statique définie à cause de cela. La JVM ne peut pas créer un autre objet de cette classe.
Par exemple,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
J'ai reçu ce message après avoir supprimé deux fichiers de la bibliothèque SRC, et quand je les ai ramenés, j'ai continué à voir ce message d'erreur.
Ma solution était: Redémarrez Eclipse. Depuis lors, je n'ai plus revu ce message :-)
Assurez-vous que cela correspond au module:app
et module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
et deux }
). Peux-tu le réparer?