NoClassDefFoundError durante il tentativo di eseguire il mio jar con java.exe -jar ... cosa c'è che non va?
-
05-07-2019 - |
Domanda
Ho un'applicazione che sto cercando di avvolgere in un barattolo per una distribuzione più semplice. L'applicazione viene compilata ed eseguita correttamente (in una finestra cmd di Windows) quando viene eseguita come un insieme di classi raggiungibili da CLASSPATH. Ma quando accumulo le mie lezioni e provo a eseguirlo con java 1.6 nella stessa finestra cmd, comincio a ottenere eccezioni:
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 cosa divertente è che LogFactory offensivo sembra essere in commons-logging-1.1.jar, che si trova nel percorso di classe specificato. Il file jar (sì, è davvero 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
Il contenuto del file 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 ...)
Sì, la registrazione comune ha la classe LogFactory. E infine, il contenuto del manifest del mio vaso:
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
Questo mi ha sconcertato e tutti i colleghi che ho assillato per più di un giorno ormai. Solo per cogliere le risposte, almeno per ora, le soluzioni di terze parti a questo sono probabilmente fuori a causa di restrizioni di licenza e politiche aziendali (ad esempio: strumenti per creare exe o confezionare barattoli). L'obiettivo finale è quello di creare un vaso che può essere copiato dalla mia finestra di Windows di sviluppo su un server Linux (con qualsiasi barattolo dipendente) e utilizzato per popolare un database (quindi i percorsi di classe potrebbero finire per essere diversi tra ambienti di sviluppo e distribuzione). Qualsiasi indizio su questo mistero sarebbe molto apprezzato!
Soluzione
L'opzione -jar si esclude a vicenda da -classpath. Guarda una vecchia descrizione qui
-jar
Esegue un programma incapsulato in un file JAR. Il primo argomento è il nome di un file JAR anziché un nome di classe di avvio. Affinché questa opzione funzioni, il manifest del file JAR deve contenere una riga del modulo Main-Class: classname. Qui, classname identifica la classe che ha il metodo main statico vuoto vuoto (String [] args) che funge da punto di partenza dell'applicazione.
Vedere la pagina di riferimento dello strumento Jar e la traccia Jar del Tutorial Java per informazioni sull'uso dei file Jar e dei manifesti file Jar.
Quando si utilizza questa opzione, il file JAR è l'origine di tutte le classi utente e le altre impostazioni del percorso delle classi utente vengono ignorate.
Un trucco rapido e sporco è quello di aggiungere il tuo percorso di classe al percorso di classe bootstrap:
-Xbootclasspath / a: path
Specifica un percorso separato da due punti di direttori, archivi JAR e archivi ZIP da aggiungere al percorso di classe bootstrap predefinito.
Tuttavia, come @Dan dice giustamente, la soluzione corretta è assicurarsi che il tuo JARs Manifesto contenga il percorso di classe per tutti i JAR di cui avrà bisogno.
Altri suggerimenti
Puoi omettere l'opzione -jar
e avviare il file jar in questo modo:
java -cp MyJar.jar; C: \ externalJars \ * mainpackage.MyMainClass
Questo è il problema che si sta verificando,
se il file JAR è stato caricato da " C: \ java \ apps \ appli.jar " ;, e il tuo file manifest ha il percorso di classe: riferimento " lib / other.jar " ;, il caricatore di classi cercherà in " C: \ java \ apps \ lib \ " per " altro.jar " ;. Non esaminerà la voce del file JAR " lib / other.jar " ;.
Soluzione: -
- Fai clic destro sul progetto, seleziona Esporta.
- Seleziona la cartella Java e in essa seleziona il file JAR eseguibile anziché il file JAR.
- Seleziona le opzioni appropriate e nella sezione Gestione libreria seleziona la terza opzione, ovvero (Copia le librerie richieste in una sottocartella accanto al JAR generato).
[ MODIFICA = la terza opzione genera una cartella oltre al vaso, la seconda opzione (" Librerie richieste dal pacchetto in JAR generato ") può anche essere usata quando hai il vaso. ]
- Fai clic su Fine e il tuo JAR viene creato nella posizione specificata insieme a una cartella che contiene i JAR menzionati nel file manifest.
-
apri il terminale, dai il percorso corretto al tuo jar ed eseguilo usando questo comando java -jar abc.jar
Ora ciò che accadrà è che il caricatore di classi cercherà nella cartella corretta i JAR referenziati poiché ora sono presenti nella stessa cartella che contiene la tua app JAR..Non c'è " java.lang.NoClassDefFoundError " eccezione generata ora.
Questo ha funzionato per me ... Spero che funzioni anche per te !!!
se usi librerie esterne nel tuo programma e provi a raggruppare tutte insieme in un file jar non è così semplice, a causa di problemi con il percorso di classe ecc.
Preferirei utilizzare OneJar per questo problema.
Ho avuto lo stesso problema con il mio vaso la soluzione
- Crea il file MANIFEST.MF:
Versione manifest: 1.0
Sigillato: vero
Percorso di classe:. lib / jarX1.jar lib / jarX2.jar lib / jarX3.jar
Classe principale: com.MainClass
- Fai clic destro sul progetto, seleziona Esporta.
seleziona esporta tutte le cartelle di output per il progetto verificato
- seleziona usando manifest esistente dallo spazio di lavoro e seleziona il file MANIFEST.MF
Questo ha funzionato per me :)
Ho scoperto quando sto usando un manifest che l'elenco di vasetti per il percorso di classe deve avere uno spazio dopo l'elenco di ogni vaso ad es. " richiesto_lib / sun / pop3.jar richiesto_lib / sole / smtp.jar " ;. Anche se è l'ultimo nell'elenco.