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?
Vous utilisez soit-jar
o-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.
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).
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
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
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