web-dev-qa-db-fra.com

Appelez "Java -jar MyFile.jar" avec l'option de chemin de classe supplémentaire

J'ai créé un fichier jar contenant tous mes trucs compilés. De plus, mon script de compilation ant copie les bibliothèques requises dans un sous-dossier "libs". La structure ressemble à ceci:

MyProgram.jar
libs/

Ainsi, lorsque j'essaie de lancer mon programme, l'erreur suivante apparaît:

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)

Pourquoi cela arrive-t-il?

74
toom

Vous utilisez soit-jaro-cp, vous ne pouvez pas combiner les deux. Si vous souhaitez placer des fichiers JAR supplémentaires sur le chemin de classe, vous devez les placer dans le manifeste du fichier JAR principal, puis utiliser Java -jar ou vous mettez le classpath complet (y compris le fichier JAR principal et ses dépendances) dans -cp et nommez explicitement la classe principale sur la ligne de commande

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

(J'utilise le dir/* syntaxe qui indique à la commande Java d’ajouter tous les .jar fichiers d'un répertoire particulier vers le chemin d'accès aux classes. Notez que le * doit être protégé de l'expansion par le shell, c'est pourquoi j'ai utilisé des guillemets simples.)

Vous indiquez que vous utilisez Ant, vous pouvez donc utiliser ant's <manifestclasspath> tâche après copier les dépendances mais avant construire le JAR.

<manifestclasspath property="myprogram.manifest.classpath" jarfile="MyProgram.jar">
  <classpath>
    <fileset dir="libs" includes="*.jar" />
  </classpath>
</manifestclasspath>

<jar destfile="MyProgram.jar" basedir="classes">
  <manifest>
    <attribute name="Main-Class" value="main.Main" />
    <attribute name="Class-Path" value="${myprogram.manifest.classpath}" />
  </manifest>
</jar>

Avec cela en place, Java -jar MyProgram.jar fonctionnera correctement et inclura également tous les fichiers JAR libs du chemin de classe.

130
Ian Roberts

Lorsque l'option -jar Est utilisée, l'option -cp Est ignorée. Le seul moyen de définir le chemin d'accès aux classes consiste à utiliser le fichier manifeste dans le fichier jar.

Il est plus facile d’utiliser simplement l’option -cp, D’ajouter votre fichier jar à cela, puis d’appeler explicitement la classe principale.

De plus, si le dossier /home/user/Java/MyProgram/jar/libs Contient des fichiers JAR (par opposition aux fichiers de classe), cela ne fonctionnera pas. Vous ne pouvez pas spécifier un dossier de fichier jar, mais vous devez spécifier chaque fichier jar individuellement dans le chemin d'accès aux classes (il est conseillé d'écrire un simple script shell pour le faire pour vous s'il existe un nombre important de fichiers jar).

17
Jonathan

Pour des tests rapides et ponctuels d'une application, vous pouvez simplement faire un lien symbolique entre les fichiers JAR de dépendance nécessaires et le répertoire contenant le fichier JAR de l'application principale.

Exemple (pour une application app.jar qui utilise la bibliothèque Eclipse SWT, qui dans mon cas a été installée dans /usr/share/Java):

$ ln -s /usr/share/Java/swt.jar .
$ Java -jar app.jar
0
ack

C'est un peu délicat. Le script suivant tente d'extraire le chemin d'accès aux classes à partir du manifeste du fichier jar, puis d'autoriser l'ajout d'entrées de chemins d'accès aux classes supplémentaires. J'avais des résultats mitigés avec cela, mais je souhaitais néanmoins partager le script afin qu'il soit parfaitement fonctionnel ici.

Le script a deux noms

  • showmanifest
  • calljar

en liant les deux fichiers avec

ln calljar showmanifest

avec calljar -h, vous pouvez voir l'utilisation.

#!/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
0
Wolfgang Fahl