前回の続きです。
前回の実験では、外部クラスへの参照があるクラスを実行した場合に、NoClassDefFoundErrorになってしまったわけですが、外部クラスを使わずにコーディングするのは無謀でしょう。「車輪の再発明」したくないですし。。。
というわけで、今度は実行可能なJARファイルを使ってテストしてみました。
使用したJavaプロジェクトは、前回とまったく同じものです。
JARファイルの作成
エクスポートを選択し、今度は「Runnable JAR File」をチョイス!
Launch configurationに指定したクラスが、jarオプションで実行した際に実行されるクラスになるようです。
これで、デスクトップに「Test_runnable.jar」が生成されました。
JARファイル実行テスト
(1)JARファイルの配備
先のJARを次の場所に設置(ちなみに前回のJARやクラスパス設定はすべて消去しました)
/home/tigertaizo/lib/Test_runnable.jar
(2)クラスパスの登録
自分のユーザー環境のプロファイルにクラスパスを登録します。
$ vim ~/.bash_profile CLASSPATH=/home/tigertaizo/lib/Test_runnable.jar:. export CLASSPATH=$CLASSPATH
即、設定を反映し、環境変数を確認します。
$ source .bash_profile $ echo $CLASSPATH /home/tigertaizo/lib/Test_runnable.jar:.
パスが通りました。
(3)実行
Javaコマンドで4つのクラスを実行してみました。
$ java tigertaizo.Test01 run Test01#main. Test01は、正常終了しました。 $ java tigertaizo.Test02 run Test02#main. Test02は、異常終了しました。 $ java tigertaizo.Test03 run Test03#main. 文字列sは、null または 空白です。 $ java tigertaizo.Test04 run Test04#main. Exception in thread "main" java.lang.NullPointerException at tigertaizo.Test04.main(Test04.java:6)
今度は、すべて想定通りに動かせましたね。
JARエクスポートの設定で、Launch configurationをTest03に設定したものを-jarオプションで実行しても、問題ないことが確認できました!
$ java -jar ~/lib/Test_runnable.jar run Test03#main. 文字列sは、null または 空白です。
これで、JARファイルについて、だいぶ理解が深まりました。
最後に、エクスポート設定で、「Library handling」というのが気になったので、こちらも確認しておきます。
こちらについては、下記のサイトにて、詳しく書かれておりました!
とりあえず、私も3つの設定ごとに実行可能JARをエクスポートしてみました。
Extract required libraries into generated JAR(生成されるJARに必須ライブラリーを抽出)
Test_runnable.jar │ ├─com │ └─google(※ファイルは省略) │ +---common │ | +---annotations │ | +---base │ | | \---internal │ | +---cache │ | +---collect │ | +---escape │ | +---eventbus │ | +---hash │ | +---html │ | +---io │ | +---math │ | +---net │ | +---primitives │ | +---reflect │ | +---util │ | | \---concurrent │ | \---xml │ \---thirdparty │ \---publicsuffix │ ├─META-INF │ │ MANIFEST.MF │ │ │ └─maven │ └─com.google.guava │ └─guava │ pom.properties │ pom.xml │ └─tigertaizo Test01.class Test02.class Test03.class Test04.class
MANIFEST.MF
Manifest-Version: 1.0 Class-Path: . Main-Class: tigertaizo.Test01
Package required libraries into generated JAR(生成されるJARに必須ライブラリーをパッケージ)
Test_runnable.jar │ guava-18.0.jar │ ├─META-INF │ MANIFEST.MF │ ├─org │ └─eclipse │ └─jdt │ └─internal │ └─jarinjarloader │ JarRsrcLoader$ManifestInfo.class │ JarRsrcLoader.class │ JIJConstants.class │ RsrcURLConnection.class │ RsrcURLStreamHandler.class │ RsrcURLStreamHandlerFactory.class │ └─tigertaizo Test01.class Test02.class Test03.class Test04.class
MANIFEST.MF
Manifest-Version: 1.0 Rsrc-Class-Path: ./ guava-18.0.jar Class-Path: . Rsrc-Main-Class: tigertaizo.Test01 Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
Copy required libraries into a sub-folder next to the generated JAR(生成されるJARの隣のサブフォルダーに必須ライブラリーをコピー)
Test_runnable.jar │ ├─META-INF │ MANIFEST.MF │ └─tigertaizo Test01.class Test02.class Test03.class Test04.class Test_runnable_lib guava-18.0.jar
MANIFEST.MF
Manifest-Version: 1.0 Class-Path: . Test_runnable_lib/guava-18.0.jar Main-Class: tigertaizo.Test01
個人的には、2番目の「生成されるJARに必須ライブラリーをパッケージ」が好みでしょうか。