Chiama “java -jar MyFile.jar” con l’opzione di percorso di class aggiuntiva

Ho creato un file jar contenente tutte le mie cose compilate. Inoltre il mio script form di ant copia le librerie richieste in una “sottocartella” libs. La struttura si presenta così:

MyProgram.jar libs/ 

Quindi quando provo a eseguire il mio programma ora ottengo il seguente errore:

 java -cp ".:/home/user/java/MyProgram/jar/libs" -jar MyProgram.jar java.lang.ClassNotFoundException: org.postgresql.Driver at java.net.URLClassLoader$1.run(URLClassLoader.java:217) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:205) at java.lang.ClassLoader.loadClass(ClassLoader.java:321) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:266) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:186) at database.PostgresQL.getConnection(PostgresQL.java:38) at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:19) at main.Main.calculateCorrelationMatrix(Main.java:51) at main.Main.main(Main.java:28) java.lang.NullPointerException at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:25) at main.Main.calculateCorrelationMatrix(Main.java:51) at main.Main.main(Main.java:28) 

Perché succede?

Puoi usare -jar o -cp , non puoi combinare i due. Se si desidera aggiungere JAR aggiuntivi sul classpath, è necessario inserirli nel manifest di JAR principale e quindi utilizzare java -jar oppure inserire il classpath completo (incluso il JAR principale e le relative dipendenze) in -cp e denominare la class principale esplicitamente sulla riga di comando

 java -cp 'MyProgram.jar:libs/*' main.Main 

(Sto usando la syntax dir/* che dice al comando java di aggiungere tutti i file .jar da una particolare directory al classpath. Si noti che * deve essere protetto dall’espansione dalla shell, che è il motivo per cui ho usato il singolo citazioni.)

Tu dici che stai usando Ant così per l’approccio manifest alternativo, puoi usare l’attività di ant dopo aver copiato le dipendenze ma prima di build il JAR.

            

Con questo, java -jar MyProgram.jar funzionerà correttamente e includerà anche tutti i file JAR di libs sul classpath.

Quando viene utilizzata l’opzione -jar l’opzione -cp viene ignorata. L’unico modo per impostare classpath è usare il file manifest nel jar.

È più semplice usare l’opzione -cp, aggiungere il file jar a questo, quindi chiamare esplicitamente la class principale.

Inoltre, supponendo che la cartella / home / user / java / MyProgram / jar / libs contenga file jar (al contrario dei file di class), questo non funzionerà. Non è ansible specificare una cartella di file jar, ma è necessario specificare ciascun file jar singolarmente nel classpath (vale la pena scrivere un semplice script di shell per farlo se esiste un numero significativo di jar).

È un po ‘complicato. Il seguente script è un tentativo di ottenere il classpath dal manifest del jar e quindi consentire di aggiungere ulteriori voci del percorso di class. Ho avuto risultati misti con questo, ma voglio comunque condividere lo script in modo che possa essere reso completamente funzionale qui.

Lo script ha due nomi

  • showmanifest
  • calljar

collegando in modo fisso i due file insieme a

 ln calljar showmanifest 

con calljar -h puoi vedere l’utilizzo.

 #!/bin/bash #set -x # show the manifest of a jar file # 2012-07-18 # author WF # # show usage # usage() { echo "usage: showmanifest (jarfile | directory jarfile) " 1>&2 echo "usage: calljar directory jarfile classpath pattern arguments" 1>&2 echo " -h|--help " 1>&2 echo " show this help and exit" 1>&2 echo " -m|--mainclass javaclass" 1>&2 echo " mainclass to use (otherwise manifest is inspected)" 1>&2 exit 1 } # # show the manifest of the given jar file # show() { dir="$1" jar="$2" fulljar=`find "$dir" -name "$jar"` cd /tmp mkdir show$$ cd show$$ jar xvf $fulljar META-INF/MANIFEST.MF cat META-INF/MANIFEST.MF cd /tmp rm -rf show$$ } # # show the classpath of the manifest # calljar() { dir="$1" jar="$2" classpath="$3" pattern="$4" arguments="$5" cmd=`show "$dir" "$jar" | awk -v extracp="$classpath" -v dir="$dir" -v pattern="$pattern" -v jar="$jar" -v mainclass="$mainclass" -v args="$arguments" ' /Main-Class: / { if (mainclass=="") mainclass=$2 } /^Class-Path:/ { incp=1; cp=$0; gsub("Class-Path: ","",cp) next } /^ .*$/ && incp { line=substr($0,2) # remove carriage return (if any) cp=cp line } END { # we do not like carriage returns gsub("\\r","",cp) gsub("\\r","",mainclass) # we do not like blanks ... gsub(" ","",cp) gsub(pattern,":"dir"/"pattern,cp) print "java -cp " extracp cp ":"dir"/"jar " " mainclass " " args } '` #echo $cmd $cmd } # echo $# arguments found: $* # parse command line options while true; do # echo "option $1" case "$1" in # options without arguments -h|--help) usage;; # for options with required arguments, an additional shift is required -m|--mainclass) mainclass=$2; shift;; (--) shift; break;; (-*) echo "$0: error - unrecognized option $1" 1>&2; usage;; (*) dir=$1;shift;break;; esac shift done #echo "argcount=$#" case $# in 0) dir=`dirname "$dir"` jar=`basename "$dir"` show "$dir" "$jar";; 1) jar="$1" show "$dir" "$jar";; 2) usage;; 3) usage;; *) jar="$1"; shift; classpath="$1"; shift; pattern="$1"; shift; arguments="$@"; #echo "mainclass=${mainclass}" #echo "classpath=${classpath}" #echo calljar "${dir}" "${jar}" "${classpath}" "$pattern" "$arguments" calljar "$dir" "$jar" "$classpath" "$pattern" "$arguments" ;; esac 

Per test rapidi e unici di un’app, è ansible semplicemente colbind i file JAR di dipendenza necessari alla directory contenente il file JAR dell’app principale.

Esempio (per un’app app.jar che utilizza la libreria SWT di Eclipse, che nel mio caso è stata installata in /usr/share/java ):

 $ ln -s /usr/share/java/swt.jar . $ java -jar app.jar