Chame “java -jar MyFile.jar” com opção de caminho de class adicional

Eu criei um arquivo jar contendo todas as minhas coisas compiladas. Além disso, meu script ant constrói copia as bibliotecas requeridas em uma subpasta “libs”. A estrutura é assim:

MyProgram.jar libs/ 

Então, quando tento executar o meu programa agora recebo o seguinte erro:

 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) 

Por que isso acontece?

Você usa -jar ou -cp , você não pode combinar os dois. Se você quiser colocar JARs adicionais no caminho de class, deverá colocá-los no manifesto do JAR principal e usar java -jar ou colocar o caminho de class completo (incluindo o JAR principal e suas dependencies) em -cp e nomear a class principal explicitamente na linha de comando

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

(Estou usando a syntax dir/* que informa ao comando java para adicionar todos os arquivos .jar de um diretório específico ao caminho de class. Observe que o * deve ser protegido da expansão pelo shell, e é por isso que usei citações.)

Você menciona que está usando o Ant assim, para a abordagem do manifesto alternativo, você pode usar a tarefa do ant depois de copiar as dependencies, mas antes de construir o JAR.

            

Com isso em vigor, o java -jar MyProgram.jar funcionará corretamente e includeá todos os arquivos JAR libs no caminho de class também.

Quando a opção -jar é usada, a opção -cp é ignorada. A única maneira de definir o caminho de class é usando o arquivo de manifesto no jar.

É mais fácil usar apenas a opção -cp, adicionar seu arquivo jar a isso e chamar explicitamente a class principal.

Além disso, supondo que a pasta / home / user / java / MyProgram / jar / libs contenha arquivos jar (em oposição a arquivos de class), isso não funcionará. Você não pode especificar uma pasta do arquivo jar, mas deve especificar cada arquivo jar individualmente no caminho de class (vale a pena escrever um script de shell simples para fazer isso para você se houver um número significativo de jars).

É um pouco complicado. O script a seguir é uma tentativa de obter o caminho de class a partir do manifesto do jar e, em seguida, permitir adicionar inputs de caminho de class extras. Eu tive resultados mistos com isso, mas quero compartilhar o script, no entanto, para que possa ser totalmente funcional aqui.

O script tem dois nomes

  • showmanifest
  • calljar

por hardlinking os dois arquivos junto com

 ln calljar showmanifest 

com calljar -h você pode ver o uso.

 #!/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 

Para testes rápidos e únicos de um aplicativo, você pode simplesmente vincular os arquivos JAR de dependência necessários ao diretório que contém o arquivo JAR do aplicativo principal.

Exemplo (para um aplicativo app.jar que usa a biblioteca Eclipse SWT, que no meu caso foi instalada em /usr/share/java ):

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