58 votes

NoClassDefFoundError en essayant d'exécuter mon jar avec java.exe -jar...qu'est-ce qui ne va pas ?

J'ai une application que j'essaie d'emballer dans un jar pour faciliter le déploiement. L'application se compile et s'exécute correctement (dans une fenêtre cmd de Windows) lorsqu'elle est exécutée comme un ensemble de classes accessibles depuis le CLASSPATH. Mais lorsque je mets mes classes en jar et que j'essaie de l'exécuter avec java 1.6 dans la même fenêtre cmd, je commence à obtenir des exceptions :

C:\dev\myapp\src\common\datagen>C:/apps/jdk1.6.0_07/bin/java.exe -classpath C:\myapp\libs\commons -logging-1.1.jar -server -jar DataGen.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    at com.example.myapp.fomc.common.datagen.DataGenerationTest.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
    ... 1 more

Ce qui est amusant, c'est que la LogFactory incriminée semble se trouver dans commons-logging-1.1.jar, qui se trouve dans le chemin de classe spécifié. Le fichier jar (oui, il est bien là) :

C:\dev\myapp\src\common\datagen>dir C:\myapp\libs\commons-logging-1.1.jar
 Volume in drive C is Local Disk
 Volume Serial Number is ECCD-A6A7

 Directory of C:\myapp\libs

12/11/2007  11:46 AM            52,915 commons-logging-1.1.jar
           1 File(s)         52,915 bytes
           0 Dir(s)  10,956,947,456 bytes free

Le contenu du fichier commons-logging-1.1.jar :

C:\dev\myapp\src\common\datagen>jar -tf C:\myapp\libs\commons-logging-1.1.jar
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/commons/
org/apache/commons/logging/
org/apache/commons/logging/impl/
META-INF/LICENSE.txt
META-INF/NOTICE.txt
org/apache/commons/logging/Log.class
org/apache/commons/logging/LogConfigurationException.class
org/apache/commons/logging/LogFactory$1.class
org/apache/commons/logging/LogFactory$2.class
org/apache/commons/logging/LogFactory$3.class
org/apache/commons/logging/LogFactory$4.class
org/apache/commons/logging/LogFactory$5.class
org/apache/commons/logging/LogFactory.class
... (more classes in commons-logging-1.1 ...)

Oui, commons-logging possède la classe LogFactory. Et enfin, le contenu du manifeste de mon jar :

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 10.0-b23 (Sun Microsystems Inc.)
Main-Class: com.example.myapp.fomc.common.datagen.DataGenerationTest
Class-Path: commons-logging-1.1.jar commons-lang.jar antlr.jar toplink
 .jar GroboTestingJUnit-1.2.1-core.jar junit.jar

Cela me laisse perplexe, ainsi que tous les collègues que j'ai mis sur écoute depuis plus d'un jour maintenant. Pour faire le tour des réponses, pour le moment du moins, les solutions tierces sont probablement exclues en raison des restrictions de licence et des politiques de l'entreprise (par exemple, les outils de création d'exe ou de conditionnement des jars). Le but ultime est de créer un jar qui peut être copié de ma boîte Windows de développement à un serveur Linux (avec tous les jars dépendants) et utilisé pour remplir une base de données (donc les classpaths peuvent être différents entre les environnements de développement et de déploiement). Tout indice sur ce mystère serait grandement apprécié !

59voto

toolkit Points 27248

L'option -jar est mutuellement exclusive de -classpath. Voir une ancienne description aquí

-jar

Exécuter un programme encapsulé dans un fichier JAR. Le premier argument est le nom d'un fichier JAR au lieu d'un nom de classe de démarrage. Pour que cette option fonctionne, le manifeste du fichier JAR doit contenir une ligne de la forme Main-Class : classname. Ici, classname identifie la classe ayant la méthode public static void main(String[] args) qui sert de point de départ à votre application.

Consultez la page de référence de l'outil Jar et la piste Jar du Tutoriel Java pour obtenir des informations sur l'utilisation des fichiers Jar et des manifestes de fichiers Jar.

Lorsque vous utilisez cette option, le fichier JAR est la source de toutes les classes utilisateur, et les autres paramètres de chemin d'accès aux classes utilisateur sont ignorés.

Une astuce rapide consiste à ajouter votre classpath au classpath de bootstrap :

-Xbootclasspath/a : chemin

Spécifiez un chemin d'accès, séparé par deux points, à des directives, des archives JAR et des archives ZIP à ajouter au chemin d'accès par défaut de la classe bootstrap.

Cependant, comme @Dan dit justement, la solution correcte est de s'assurer que votre JARs Manifest contient le classpath de tous les JARs dont il aura besoin.

31voto

g_tom Points 111

Vous pouvez omettre le -jar et lancez le fichier jar comme ceci :

java -cp MyJar.jar;C:\externalJars\* mainpackage.MyMainClass

18voto

Gautam M. Points 736

C'est le problème qui se pose,

si le fichier JAR a été chargé depuis " C:\java\apps\appli.jar "et que votre fichier manifeste comporte la référence Class-Path : "lib/other.jar", le chargeur de classes cherchera dans " C:\java\apps\lib\ "pour "other.jar". Il ne regardera pas l'entrée du fichier JAR "lib/other.jar".

Solution : -

  1. Cliquez à droite sur le projet, sélectionnez Exporter.
  2. Sélectionnez le dossier Java et dans celui-ci sélectionnez Runnable JAR File au lieu de JAR file.
  3. Sélectionnez les options appropriées et dans la section Library Handling, sélectionnez la troisième option, à savoir (Copier les bibliothèques requises dans un sous-dossier à côté du JAR généré).

[ EDIT \= La 3ème option génère un dossier en plus du jar, la 2ème option ("Package required libraries into generated JAR") peut aussi être utilisée puisque vous avez le jar. ]

  1. Cliquez sur Terminer et votre JAR est créé à l'emplacement spécifié, ainsi qu'un dossier contenant les JARS mentionnés dans le fichier manifeste.
  2. ouvrez le terminal, donnez le bon chemin à votre jar et exécutez-le en utilisant cette commande java -jar abc.jar

    Maintenant, le chargeur de classe cherchera dans le bon dossier les JARS référencés puisqu'ils sont maintenant présents dans le même dossier que celui qui contient le JAR de votre application. Il n'y a pas d'exception "java.lang.NoClassDefFoundError" lancée maintenant.

Cela a marché pour moi... J'espère que cela fonctionnera pour vous aussi !!!

3voto

flash Points 3169

Si vous utilisez des bibliothèques externes dans votre programme et que vous essayez de les regrouper dans un fichier jar, ce n'est pas si simple, à cause des problèmes de classpath, etc.

Je préfère utiliser OneJar pour ce numéro.

0voto

Mary C Points 46

J'ai constaté, lorsque j'utilise un manifeste, que la liste des jars pour le classpath doit comporter un espace après la liste de chaque jar, par exemple "required_lib/sun/pop3.jar required_lib/sun/smtp.jar ". Même si c'est le dernier de la liste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X