web-dev-qa-db-fra.com

NoClassDefFoundError lors de la tentative d'exécution de mon fichier jar avec Java.exe -jar ... qu'est-ce qui ne va pas?

J'essaie de placer une application dans un pot pour un déploiement plus facile. L'application se compile et s'exécute correctement (dans une fenêtre de commande Windows) lorsqu'elle est exécutée sous la forme d'un ensemble de classes accessibles à partir de CLASSPATH. Mais lorsque je lance mes classes et que je tente 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

La chose amusante est que la LogFactory incriminée semble être dans commons-logging-1.1.jar, qui se trouve dans le chemin de classe spécifié. Le fichier jar (ouais, c'est vraiment 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 a la classe LogFactory. Et enfin, le contenu du manifeste de mon pot:

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 m'a laissé perplexe, et tous les collègues que j'ai rencontrés depuis plus d'un jour maintenant. Juste pour cerner les réponses, du moins pour le moment, les solutions tierces à ce problème sont probablement inexpliquées en raison de restrictions en matière de licences et de politiques d'entreprise (par exemple, des outils permettant de créer des exes ou d'emballer des bocaux). Le but ultime est de créer un fichier jar pouvant être copié de mon environnement Windows de développement sur un serveur Linux (avec tous les fichiers jar dépendants) et utilisé pour remplir une base de données (les classpaths peuvent donc être différents entre les environnements de développement et de déploiement). Tout indice sur ce mystère serait grandement apprécié!

55
Ogre Psalm33

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

-pot

Exécutez 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 Classe-principale: nom de la classe. Ici, classname identifie la classe ayant la méthode principale publique statique (String [] args) qui sert de point de départ à votre application.

Reportez-vous à la page de référence de l'outil Jar et à la piste Jar du Java Tutorial pour plus d'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 d'utilisateurs. Les autres paramètres de chemin d'accès aux classes d'utilisateurs sont ignorés.

Un hack rapide et sale consiste à ajouter votre chemin de classe au chemin de classe bootstrap:

-Xbootclasspath/a: chemin

Spécifiez un chemin séparé de deux lignes de directires, archives JAR et archives Zip à ajouter au chemin de classe par défaut bootstrap.

Toutefois, comme @ Dan le dit à juste titre, la solution correcte consiste à vous assurer que le manifeste des fichiers JAR contient le chemin d'accès aux classes pour tous les fichiers JAR dont il aura besoin.

56
toolkit

Vous pouvez omettre l'option -jar et démarrer le fichier jar comme suit:

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

28
g_tom

C'est le problème qui se pose,

si le fichier JAR a été chargé à partir de "C:\Java\apps\appli.jar" et que votre fichier manifeste a le chemin d'accès aux classes: référence "lib/other.jar", le chargeur de classes examinera dans "C:\Java\apps\lib\"pour" other.jar ". Il ne regardera pas l'entrée de fichier JAR "lib/other.jar".

Solution:-

  1. Faites un clic droit sur le projet, sélectionnez Exporter.
  2. Sélectionnez Dossier Java et sélectionnez le fichier JAR exécutable au lieu du fichier JAR.
  3. Sélectionnez les options appropriées et, dans la section Gestion des bibliothèques, sélectionnez la 3ème option, c.-à-d. (Copier les bibliothèques requises dans un sous-dossier situé à côté du fichier JAR généré).

[EDIT= La 3ème option génère un dossier en plus du jar, la 2ème option ("Créer les bibliothèques requises dans le JAR généré") peut également être utilisée avec le jar. ]

  1. Cliquez sur Terminer. Votre fichier JAR est créé à l'emplacement spécifié, ainsi qu'un dossier contenant les fichiers JAR mentionnés dans le fichier manifeste.
  2. ouvrez le terminal, indiquez le chemin correct vers votre fichier jar et exécutez-le à l'aide de cette commande Java -jar abc.jar 

    Maintenant, que va-t-il se passer, le chargeur de classe va chercher dans le bon dossier les fichiers JARS référencés, car ils sont maintenant présents dans le même dossier que celui qui contient votre JAR app ..

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

15
Gautam Mandsorwale

si vous utilisez des bibliothèques externes dans votre programme et que vous essayez de regrouper tous vos fichiers dans un fichier jar, ce n'est pas si simple, en raison de problèmes de chemin d'accès aux classes, etc.

Je préférerais utiliser OneJar pour ce problème.

4
flash

j'ai eu le même problème avec mon pot la solution 

  1. Créez le fichier MANIFEST.MF:

Manifest-Version: 1.0

Scellé: vrai

Chemin de classe:. lib/jarX1.jar lib/jarX2.jar lib/jarX3.jar

Classe principale: com.MainClass

  1. Faites un clic droit sur le projet, sélectionnez Exporter.

sélectionner exporter tous les dossiers sortants pour le projet vérifié

  1. sélectionnez en utilisant un manifeste existant depuis l'espace de travail et sélectionnez le fichier MANIFEST.MF

Cela a fonctionné pour moi :) 

2
mouhcine

J'ai constaté, lorsque j'utilise un manifeste, que la liste des fichiers jar pour le chemin de classe doit avoir un espace après la liste de chaque fichier, par exemple "requis_lib/Sun/pop3.jar requis_lib/Sun/smtp.jar". Même si c'est le dernier de la liste. 

0
Mary C