コンパイル済みのものをすべて含むjarファイルを作成しました。さらに、antビルドスクリプトは、必要なライブラリをサブフォルダー「libs」にコピーします。構造は次のようになります。
MyProgram.jar
libs/
したがって、プログラムを実行しようとすると、次のエラーが表示されます。
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)
なぜこれが起こるのですか?
either-jar
または-cp
を使用すると、2つを組み合わせることはできません。クラスパスに追加のJARを配置する場合は、メインJARのマニフェストに追加してからJava -jar
を使用するか、-cp
に完全なクラスパス(メインJARとその依存関係を含む)を配置する必要があります。コマンドラインでメインクラスに明示的に名前を付けます
Java -cp 'MyProgram.jar:libs/*' main.Main
(私はdir/*
構文を使用して、特定のディレクトリのすべての.jar
ファイルをクラスパスに追加するようJava
コマンドに指示します。*
はシェルによる拡張。これが、単一引用符を使用した理由です。)
Antを使用していることに言及しているため、代替マニフェストアプローチでは、antの<manifestclasspath>
タスクを使用できますafter依存関係をコピーしますbefore 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>
これにより、Java -jar MyProgram.jar
は正常に機能し、クラスパス上のlibs
JARファイルもすべて含まれます。
-jar
オプションが使用される場合、-cp
オプションは無視されます。クラスパスを設定する唯一の方法は、jar内のマニフェストファイルを使用することです。
-cp
オプションを使用してjarファイルを追加し、メインクラスを明示的に呼び出す方が簡単です。
また、/home/user/Java/MyProgram/jar/libs
フォルダーにjarファイル(クラスファイルではなく)が含まれていると仮定すると、これは機能しません。 jarファイルのフォルダーを指定することはできませんが、クラスパスで各jarファイルを個別に指定する必要があります(かなりの数のjarがある場合は、これを行う単純なシェルスクリプトを作成する価値があります)。
アプリの1回限りの簡単なテストのために、必要な依存関係JARファイルをメインアプリJARファイルを含むディレクトリにシンボリックリンクするだけです。
例(私の場合はapp.jar
にインストールされたEclipse SWTライブラリを使用するアプリ/usr/share/Java
の場合):
$ ln -s /usr/share/Java/swt.jar .
$ Java -jar app.jar
少し注意が必要です。次のスクリプトは、jarのマニフェストからクラスパスを取得し、追加のクラスパスエントリを追加できるようにする試みです。これにはさまざまな結果がありましたが、スクリプトを共有したいので、ここで完全に機能するようにします。
スクリプトには2つの名前があります
2つのファイルを一緒にハードリンクすることにより
ln calljar showmanifest
calljar -hを使用すると、使用法を確認できます。
#!/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