2016-04-26 2 views
0

Also, ich habe den ganzen Tag mit diesem Problem verbracht.
Ich bin mir sicher, dass ich den korrekten Klassenpfad verwende.
Auch habe ich andere Pakete als Abhängigkeiten, und sie funktionieren perfekt.Java: NoClassDefFoundError: org/json/JSONException

Ich habe eine Klasse, die org.json verwendet. *
Es gibt auch einige andere äußere Pakete in dieser Klasse verwendet.
All diese Abhängigkeiten werden als JAR-Dateien in meinem/path/to/libs/abgelegt.
json-20160212.jar ist unter ihnen.

ich mit meiner Quellen bin Kompilieren geht

javac \ 
    -cp "src/:/path/to/libs/json-20160212.jar:/path/to/libs/other.jar:/path/to/libs/another.jar" \ 
    -d dst/ \ 
    src/com/example/Source.java 

Compilation ohne Probleme.
Dann erstelle ich Jar aus meinen Klassen-Dateien.
Manifest:

Main-Class: com.example.Source 
Class-Path: /path/to/libs/json-20160212.jar 
    /path/to/libs/other.jar 
    /path/to/libs/another.jar 

Befehlszeile:
jar cfm output.jar manifest -C dst/ ./com

Ich erhalte Glas mit diesem Manifest:

Manifest-Version: 1.0 
Class-Path: /path/to/libs/json-20160212.jar /path/to/libs/other.jar /p 
ath/to/libs/another.jar 
Created-By: 1.7.0_101 (Oracle Corporation) 
Main-Class: com.example.Source 

Wie ich verstanden habe, das ist ok für manifest kompiliert habe geteilte Linien.

Nun, ich meine app von der Kommandozeile ausgeführt wird und diese Fehlermeldung erhalten:

Exception in thread "Thread-0" java.lang.NoClassDefFoundError: org/json/JSONException 
    at com.example.Source.run(Source.java:30) 
Caused by: java.lang.ClassNotFoundException: org.json.JSONException 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    ... 1 more 

Wie ich weiß, das bedeutet, dass org.json.JSONException bei der Kompilierung in Ordnung war, aber zur Laufzeit fehlt .
Aber was muss ich mit dieser Info machen?
Ich habe diese Datei. Es war während der Kompilierung und zur Laufzeit an seinem Platz.
Auch gibt es andere Abhängigkeiten, und ihre Gläser sind auch an diesem Ort.

Wenn ich JSON-Nutzung aus meiner App entfernen, funktioniert alles einwandfrei.
Also kann ich Schluss machen, dass es das Paket org.json selbst ist, das das Problem macht.

Was muss ich tun, damit es funktioniert?

UPDATE

Jetzt habe ich gemacht dies ändert:

Meine Verzeichnisstruktur:

libs/ 
    json-20160212.jar 
    other.jar 
    another.jar 
src/ 
    com/ 
     example/ 
      Source.java 
dst/ 

Manifest:

Main-Class: com.example.Source 
Class-Path: libs/json-20160212.jar 
    libs/other.jar 
    libs/another.jar 

Compilation:

javac \ 
    -cp "src/:libs/json-20160212.jar:libs/other.jar:libs/another.jar" \ 
    -d dst/ \ 
    src/com/example/Source.java 

Jarchiving:

jar cfm dst/output.jar manifest -C dst/ ./com ./libs 

Ich erhalte Glas mit der Struktur, wie ausgenommen:

META-INF/ 
META-INF/MANIFEST.MF 
com/ 
com/example/ 
com/example/Source.class 
libs/ 
libs/json-20160212.jar 
libs/other.jar 
libs/another.jar 

Und ich bin es mit java -jar dst/output.jar läuft.
Ergebnis ist das gleiche: java.lang.NoClassDefFoundError: org/json/JSONException

+0

Überprüfen Sie das resultierende Glas auf seinen Inhalt. Befindet sich das JSON-Glas zum Beispiel tatsächlich in /path/to/libs/json-20160212.jar? – ManoDestra

+0

Ich denke, Sie sind nicht spezifische lib in Ihrem Projekt hinzufügen. Überprüfen Sie es und stellen Sie sicher, dass alle benötigten Gläser alle im Projekt enthalten sind. –

+0

Mit Ihrem Jar-Befehl oben ('jar cfm output.jar manifest -C dst /./Com') sieht es so aus, als würden Sie die Bibliotheksabhängigkeiten nicht zu Ihrem jar hinzufügen. Enthalten Sie Pfad/zu/lib sowie Ihre Klassen und es sollte danach gut funktionieren. – ManoDestra

Antwort

0

So ist die Lösung:

Wie ich verstehe habe, ist der einzige Weg, um den Inhalt der JAR-Dateien zuzugreifen, die in Ihrem Glas sind, ist Ihre eigenen Klassenlader zu schreiben.
Ohne es müssen JAR-Dateien extrahiert werden und dieser extrahierte Inhalt muss in output.jar enthalten sein.

+0

Sie sollten dies nicht tun müssen (wie ich bereits sagte, ich habe bereits eine JAR mit einem anderen Glas, richtig referenziert und es lief gut), aber es gibt sicherlich einige Werkzeuge, die Ihnen erlauben, dies zu tun, wie sbt-Assembly (ich benutze dieses in der Arbeit) und OneJar. Sie verwenden Entscheidungsmechanismen, um mit Klassenkonflikten umzugehen, und sie erweitern alle Klassen von abhängigen Gläsern in Ihr einzelnes fettes Glas. Aktualisierte meine Antwort mit einigen weiteren Ratschlägen bezüglich Fettglaslösungen. – ManoDestra

+1

Ich denke, Sie konnten Ihr jar ausführen, da die Dateistruktur in Ihrem jar dieselbe ist wie in Ihrem Projektverzeichnis. Deine libs (Abhängigkeiten-jars) wurden also nicht aus dem jar, sondern aus deinem lokalen Dateisystem genommen. Versuchen Sie, Ihr Ergebnisglas an den unabhängigen Ort zu verschieben und auszuführen. – seelts

+0

Schauen Sie sich auch die offizielle Dokumentation an: http://docs.oracle.com/javase/tutorial/deployment/jar/downman.html. Der erste Hinweis besagt: "Der Klassenpfad-Header verweist auf Klassen oder JAR-Dateien im lokalen Netzwerk, nicht auf JAR-Dateien in der JAR-Datei oder auf über Internetprotokolle erreichbare Klassen. Zum Laden von Klassen in JAR-Dateien innerhalb einer JAR-Datei in den Klassenpfad , Sie müssen benutzerdefinierten Code schreiben, um diese Klassen zu laden. " Wie auch immer, vielen Dank! Ihre Antwort gab mir die Richtung zur Lösung. – seelts

1

Das Problem ist Ihre Laufzeit Klassenpfad. Es gibt keine Magie mit diesem Fehler. Es bedeutet ganz einfach, dass sich org.json.JSONException nicht auf Ihrem Klassenpfad für die Laufzeit befindet. Suchen Sie das Jar, das diese Klasse enthält, und fügen Sie es in Ihren Klassenpfad zur Laufzeit ein.

Beachten Sie, dass die für die Laufzeit benötigten jars/classes nicht unbedingt mit denen identisch sind, die zum Kompilieren benötigt werden. In Ihrem Klassenpfad für die Laufzeit benötigen Sie häufig mehr als den Klassenpfad für die Kompilierung. Wenn JSONException im Code, den Sie kompilieren, nicht explizit verwendet wird, muss es nicht in Ihrem Kompilierungsklassenpfad enthalten sein. Wenn jedoch eine der Abhängigkeiten zu Ihrem Code JSONException benötigt und sich nicht auf Ihrem Klassenpfad befindet, erhalten Sie einen NoClassDefFoundError.

Ein anderes Problem, das möglicherweise auftreten kann, ist, dass Sie 2 verschiedene Versionen des Json-Jar auf Ihrem Klassenpfad haben. Normalerweise wird die erste Version der Klasse im Klassenpfad geladen und die andere ignoriert. Wenn das erste Jar nicht die Version/Signatur von JSONException hatte, die Sie benötigten, aber die zweite, würde die korrekte Klasse immer noch ignoriert werden, da sie weiter unten im Klassenpfad lag.

1

Das Problem scheint zu sein, dass Sie die abhängigen Gläser zu Ihrem resultierenden Glas nicht hinzufügen.

ich einen ähnlichen Test jar erstellt haben, mit der folgenden Struktur (Überprüfung jar tf mit) ...

META-INF/
META-INF/MANIFEST.MF
BeanIt.class
TestBean.class
lib/
lib/opencsv-3.7.jar
lib/commons-lang3-3.4.jar

Mein Manifest ...

Main-Class: BeanIt
Class-Path: lib/opencsv-3.7.jar lib/commons-lang3-3.4.jar

Um dieses Glas zu schaffen , müssen Sie einen Befehl etwas ähnliches wie diese ...

jar cfm App.jar MANIFEST.MF BeanIt.class TestBean.class lib 

Sie können sehen, dass ich meine lib folde hinzugefügt habe r an das Jar und bezog sich auf seinen Inhalt auf dem Klassenpfad im Manifest.

So können Sie Ihre vorhandene lib aktualisieren, so ...

jar uf App.jar path 

Pfad ist der Stammpfad Ihres Verzeichnisses path/to/lib. Und es wird einfach das zu Ihrem Glas hinzufügen.

Sie können Ihr Glas zuerst überprüfen mit jar tf, um zu sehen, was es enthält.

Wenn Sie immer noch Schwierigkeiten haben, es zum Laufen zu bekommen, dann können Sie sich eine "FAT JAR" -Lösung anschauen, bei der Sie alle internen JARS-Klassen erweitern und alle zu einem JAR zusammenfassen, das alle notwendigen Klassen enthält. Sie verwenden Entscheidungsmechanismen, um Klassenkonflikte in verschiedenen JARs zu behandeln. Tools wie sbt-assembly oder OneJar sind möglicherweise das, was Sie hier benötigen, wenn Sie nicht in der Lage sind, Ihr JAR so zu entwickeln, wie Sie es erwarten.

+0

Ich habe den ursprünglichen Beitrag aktualisiert. Bitte sehen Sie es sich an. – seelts

+0

Ist die erforderliche Klasse (org.json.JSONException) definitiv in Ihrem json-20160212.jar? Überprüfen Sie auch das Gehäuse von JSONException, falls es stattdessen JsonException sein sollte. Solange sich diese Klasse in Ihrem json jar befindet, befindet sich das json jar innerhalb des jar, auf das über das Manifest im Klassenpfad verwiesen wird und das korrekt von Ihrer Aufrufklasse referenziert wird. Dann sollten Sie gut sein. Stellen Sie sicher, dass Sie auch eine Klasse aus einem Ihrer anderen Gläser anrufen können. Wenn das in Ordnung ist, handelt es sich wahrscheinlich um ein Problem, bei dem die Groß-/Kleinschreibung beachtet wird oder ein Klassenproblem fehlt. – ManoDestra

+0

Werfen Sie einen Blick auf meine Antwort: http://stackoverflow.com/a/36886634/858602 – seelts