72 Stimmen

NoClassDefFoundError beim Versuch, mein jar mit java.exe -jar auszuführen...was ist los?

Ich habe eine Anwendung, die ich versuche, in ein Jar für einfachere Bereitstellung zu verpacken. Die Anwendung kompiliert und läuft gut (in einem Windows-Cmd-Fenster), wenn als eine Reihe von Klassen aus dem CLASSPATH erreichbar ausgeführt. Aber wenn ich meine Klassen in ein Jar packe und versuche, sie mit Java 1.6 im gleichen cmd-Fenster auszuführen, erhalte ich Ausnahmen:

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

Das Seltsame ist, dass die fehlerhafte LogFactory in commons-logging-1.1.jar enthalten zu sein scheint, die sich im angegebenen Klassenpfad befindet. Die jar-Datei (ja, sie ist wirklich da):

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

Der Inhalt der Datei 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 ...)

Ja, commons-logging hat die LogFactory-Klasse. Und schließlich der Inhalt des Manifests meines Jars:

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

Das hat mich und alle Mitarbeiter, die ich seit mehr als einem Tag genervt habe, verblüfft. Nur um die Antworten zusammenzufassen: Zumindest im Moment sind Lösungen von Drittanbietern aufgrund von Lizenzbeschränkungen und Unternehmensrichtlinien (z.B.: Tools zum Erstellen von Exe-Dateien oder zum Verpacken von Jars) wahrscheinlich nicht möglich. Das ultimative Ziel ist es, ein Jar zu erstellen, das von meinem Windows-Entwicklungssystem auf einen Linux-Server kopiert werden kann (mit allen abhängigen Jars) und zum Auffüllen einer Datenbank verwendet werden kann (daher können die Klassenpfade zwischen Entwicklungs- und Bereitstellungsumgebung unterschiedlich sein). Für jeden Hinweis auf dieses Rätsel wären wir sehr dankbar!

65voto

toolkit Punkte 48653

Die Option -jar schließt sich mit -classpath gegenseitig aus. Siehe eine alte Beschreibung aquí

-jar

Ausführen eines Programms, das in einer JAR-Datei gekapselt ist. Das erste Argument ist der Name einer JAR-Datei anstelle des Namens einer Startklasse. Damit diese Option funktioniert, muss das Manifest der JAR-Datei eine Zeile der Form Main-Class: classname enthalten. Hier identifiziert classname die Klasse mit der Methode public static void main(String[] args), die als Startpunkt Ihrer Anwendung dient.

Informationen über die Arbeit mit Jar-Dateien und Jar-Dateimanifesten finden Sie auf der Referenzseite des Jar-Tools und im Jar-Trail des Java-Tutorials.

Wenn Sie diese Option verwenden, ist die JAR-Datei die Quelle für alle Benutzerklassen, und andere Pfadeinstellungen für Benutzerklassen werden ignoriert.

Ein schneller und schmutziger Hack ist es, Ihren Klassenpfad an den Bootstrap-Klassenpfad anzuhängen:

-Xbootclasspath/a: Pfad

Geben Sie einen durch Doppelpunkte getrennten Pfad von Directires, JAR-Archiven und ZIP-Archiven an, der an den Standard-Bootstrap-Klassenpfad angehängt wird.

Da jedoch @Dan Richtig ist, dass die richtige Lösung darin besteht, sicherzustellen, dass das JAR-Manifest den Klassenpfad für alle benötigten JARs enthält.

2 Stimmen

Es wäre besser, einen Klassenpfad im Manifest des JAR anzugeben. Der Bootklassenpfad ist für das Ersetzen von Systemklassen gedacht.

0 Stimmen

Stimmt - ich werde es ändern, um klarzustellen, dass dies nur ein Workaround ist.

0 Stimmen

Aha! Das ist es! Ich wusste, dass ich etwas Einfaches übersehen haben musste. Nur hat hier niemand genug mit Gläsern gearbeitet, um meinen Fehler zu bemerken!

42voto

g_tom Punkte 371

Sie können die -jar und starten Sie die jar-Datei wie folgt:

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

2 Stimmen

Danke, Sie haben mich davor bewahrt, ein riesiges jar neu zu kompilieren, das vergessen hat, seine Abhängigkeiten einzuschließen. Alle anderen im Internet sagen, dass man nicht beides verwenden kann -classpath et -jar aber das tun Sie dort eindeutig.

2 Stimmen

Heilige Scheiße, das ist großartig. Ich danke euch!

2 Stimmen

Nur zur Klarstellung: Die Optionen -jar und -classpath werden hier nicht beide verwendet. Vielmehr akzeptiert die Option -classpath Jars und Wildcards: -cp <Klassensuchpfad von Verzeichnissen und zip/jar-Dateien> -classpath <Klassensuchpfad von Verzeichnissen und zip/jar-Dateien> Eine durch : getrennte Liste von Verzeichnissen, JAR-Archiven und ZIP-Archiven, die nach Klassendateien durchsucht werden sollen.

21voto

Gautam Mandsorwale Punkte 1550

Das ist das Problem, das hier auftritt,

wenn die JAR-Datei von "" geladen wurde C:\java\apps\appli.jar ", und Ihre Manifestdatei hat den Class-Path: Verweis "lib/other.jar", sucht der Classloader in " C:\java\apps\lib\ " für "andere.jar". Der JAR-Datei-Eintrag "lib/other.jar" wird nicht berücksichtigt.

Lösung:-

  1. Klicken Sie mit der rechten Maustaste auf das Projekt und wählen Sie Exportieren.
  2. Wählen Sie den Java-Ordner und darin die Option Runnable JAR File anstelle von JAR file.
  3. Wählen Sie die richtigen Optionen aus und wählen Sie im Abschnitt Library Handling die 3. Option, d.h. (Copy required libraries into a sub-folder next to the generated JAR).

[ EDITAR \= 3. Option generiert einen Ordner zusätzlich zum JAR, 2. Option ("Package required libraries into generated JAR") kann auch verwendet werden, wenn man das JAR hat. ]

  1. Klicken Sie auf Fertig stellen und Ihr JAR wird an der angegebenen Position zusammen mit einem Ordner erstellt, der die in der Manifestdatei genannten JARS enthält.
  2. Öffnen Sie das Terminal, geben Sie den richtigen Pfad zu Ihrem jar ein und führen Sie es mit diesem Befehl java -jar abc.jar aus

    Jetzt wird der Klassenlader im richtigen Ordner nach den referenzierten JARS suchen, da sie jetzt im selben Ordner vorhanden sind, der Ihr App-JAR enthält, und es wird keine "java.lang.NoClassDefFoundError"-Ausnahme mehr ausgelöst.

Das hat bei mir funktioniert... Hoffentlich funktioniert es auch bei dir!!!

0 Stimmen

Ihre Antwort ist korrekt, aber mit der 3. Option wird ein Ordner zusätzlich zum JAR generiert, ich denke, dass die 2. Option ("Package required libraries into generated JAR") die bessere ist, da Sie nur das JAR haben. Trotzdem hast du meine Stimme ;)

3voto

flash Punkte 6588

Wenn Sie externe Bibliotheken in Ihrem Programm verwenden und versuchen, alles in eine Jar-Datei zu packen, ist das nicht so einfach, weil es Probleme mit dem Klassenpfad gibt usw.

Ich würde es vorziehen, die EinGlas für diese Ausgabe.

0 Stimmen

Ich habe mir OneJar ein wenig angesehen. Das könnte eine Möglichkeit sein - die Lizenz scheint ziemlich einfach zu sein. Aber ich müsste es trotzdem dort, wo ich arbeite, "genehmigen" lassen, um es verwenden zu können.

3voto

mouhcine Punkte 61

Ich hatte das gleiche Problem mit meinem Glas die Lösung

  1. Erstellen Sie die Datei MANIFEST.MF:

Manifest-Version: 1.0

Versiegelt: wahr

Klassen-Pfad: . lib/jarX1.jar lib/jarX2.jar lib/jarX3.jar

Hauptklasse: com.MainClass

  1. Klicken Sie mit der rechten Maustaste auf das Projekt und wählen Sie Exportieren.

Wählen Sie für das geprüfte Projekt die Option Alle Ausgangsordner exportieren

  1. Wählen Sie Vorhandenes Manifest aus dem Arbeitsbereich verwenden und wählen Sie die Datei MANIFEST.MF

Das hat bei mir funktioniert :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X