2013-04-10 10 views
50

コンパイル済みのすべてのものを含むjarファイルを作成しました。さらに、私のantビルドスクリプトは、必要なlibsをサブフォルダ "libs"にコピーします。クラスパスオプションを追加して "java -jar MyFile.jar"を呼び出します

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) 

これはなぜ起こるのでしょうか。構造は次のようになりますか

答えて

100

、次の2つを組み合わせることはできません。追加のJARをクラスパスに配置する場合は、メインのJARのマニフェストに配置し、次にjava -jarを使用するか、フルJARとその依存関係を含む完全なクラスパスを-cpに入れ、主クラスをコマンドライン

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

(私はjavaコマンドは、クラスパスに特定のディレクトリからすべての.jarファイルを追加するように指示dir/*構文を使用しています。*は、シェルによって展開から保護されなければならないことに注意してくださいなぜ私は一重引用符を使用しましたか)

代わりのマニフェストのアプローチのためにAntを使用しているので、タスクの後にの依存関係はコピーされますが、の前にはが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ファイルが含まれます。

+0

上記に加えて、または、MANIFEST.MFファイルに必要なjarエントリを追加することを考えます。 –

+0

@HimanshuBhardwaj確かに、私は ' 'を使ってそれを行う方法の例を追加しました –

+0

ちょっと更新をほんの少し後に見ました。 –

7

-jarオプションを使用すると、-cpオプションは無視されます。クラスパスを設定する唯一の方法は、JARのマニフェストファイルを使用することです。

-cpオプションを使用するだけで簡単にjarファイルを追加して、明示的にメインクラスを呼び出すことができます。

また、/ home/user/java/MyProgram/jar/libsフォルダに(クラスファイルではなく)jarファイルが含まれていると仮定すると、これは機能しません。 jarファイルのフォルダを指定することはできませんが、各jarファイルをクラスパスで個別に指定する必要があります(かなりの数のjarがある場合は、これを行うための単純なシェルスクリプトを書く価値があります)。あなたは-jarまたは-cpのいずれかを使用

0

少しトリッキーです。次のスクリプトは、jarのマニフェストからクラスパスを取得し、余分なクラスパスエントリを追加する試みです。私はこれと結果を混在させましたが、スクリプトを共有したいので、ここで完全に機能するようにしてください。

スクリプトは、使用状況を見ることができます-h calljarで

ln calljar showmanifest 

と一緒 を2つのファイルをハードリンクすることによって二つの名前

  • showmanifest
  • calljar

を持っています。アプリの迅速、一回限りのテストのために

#!/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="[email protected]"; 
    #echo "mainclass=${mainclass}" 
    #echo "classpath=${classpath}" 

    #echo calljar "${dir}" "${jar}" "${classpath}" "$pattern" "$arguments" 
    calljar "$dir" "$jar" "$classpath" "$pattern" "$arguments" 
    ;; 
esac 
0

、あなたは単にメインアプリのJARファイルを含むディレクトリに必要な依存関係JARファイルをシンボリックリンクすることができます。

例(私の場合は/usr/share/javaにインストールされたEclipseのSWTライブラリを使用し、アプリapp.jar用):

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