Eclipseで作成した実行可能Jarの違い

メモ:

Eclipseで実行可能なJarファイルを作成できるのですが、作成可能な3つのタイプに違いがある事が分かりましたので、まとめていきたいと思います。 「なぜ」というところまでは分かっていないのですが、DocuShareというアプリケーションを使ったシステム開発を行った際にたどり着いた結果です。

SceneBuilderのインストール

「Eclipse上で実行できるのに、配布したら動かない!!なぜだー!」という感じで、次のエラーが出力され調査を開始しました。

com.xerox.docushare.DSException: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.net.MalformedURLException: unknown protocol: rsrc; nested exception is: 
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.net.MalformedURLException: unknown protocol: rsrc; nested exception is: 
com.xerox.docushare.DSException: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.net.MalformedURLException: unknown protocol: rsrc; nested exception is: 
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.net.MalformedURLException: unknown protocol: rsrc
at com.xerox.docushare.impl.DSFactorySpiImpl.createServer(DSFactorySpiImpl.java:70)
at com.xerox.docushare.DSFactory.createServer(DSFactory.java:68)
at jp.co.tenryu_aero.hoge.QualityRecordEcm.docushareConnect(QualityRecordEcm.java:89)
at jp.co.tenryu_aero.hoge.hoge.main(hoge.java:49) [rsrc:./:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
at java.lang.reflect.Method.invoke(Unknown Source) 
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58) [hoge.jar:na]

結論から行くと、JarRsrcLoaderから実行されると動かないという事が分かったのですが、実行可能Jarの作り方によって、MANIFEST.MFファイルに書かれるMain-Classが違ってきます。 Eclipseで、実行可能Jarを作成するには次の3つの方法が用意されています。

  • 生成されるJARに必須ライブラリーを抽出
  • 生成されるJARに必須ライブラリーをパッケージ
  • 生成されるJARの隣のサブフォルダーに必須ライブラリーをコピー

それでは、3つある実行可能Jarのエクスポートを確認していきます。 最初に、エクスポートするプロジェクトのディレクトリ構造は次の物とします。

HelloWorld
  |- Src
      |- Hello.java
  |- lib
      |- dsapi.jar
      |- jdom-1.1.3.jar

生成されるJARに必須ライブラリーを抽出

「生成されるJARに必須ライブラリーを抽出」を選択して実行可能Jarを作成するとJarファイルの中は次の構造となります。

Hello.jar
  |- com
      |- xerox
         |- docushare
            |- ...
  |- META-INF
      |- MANIFEST.MF
      |- info.xml
  |- org
      |- jdom
         |- adapters
            |- AbstractDOMAdapter.class
            |- ...
  |- Hello.class

MANIFEST.MFの中は次のような構成。

Manifest-Version: 1.0
Class-Path: .
Main-Class: Hello

Name: org/jdom/
Specification-Title: JDOM Classes
Implementation-Title: org.jdom
Implementation-Version: 1.1.3
Specification-Version: 1.0
Specification-Vendor: jdom.org
Implementation-Vendor: jdom.org

Name: org/jdom/xpath/
...

生成されるJARに必須ライブラリーをパッケージ

「生成されるJARに必須ライブラリーをパッケージ」を選択して実行可能Jarを作成するとJarファイルの中は次の構造となります。

Hello.jar
  |- META-INF
      |- MANIFEST.MF
  |- org
      |- eclipse
         |- jdt
            |- internal
               |- jarinjarloader
                  |- JarRsrcLoader.class
                  |- ...
  |- Hello.class
  |- dsapi.jar
  |- jdom-1.1.3.jar

MANIFEST.MFの中は次のような構成。

Manifest-Version: 1.0
Rsrc-Class-Path: ./ dsapi.jar jdom-1.1.3.jar
Class-Path: .
Rsrc-Main-Class: Hello
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader

ここでポイントとなるのがMain-ClassがJarRsrcLoaderになっている部分です。

生成されるJARの隣のサブフォルダーに必須ライブラリーをコピー

「生成されるJARの隣のサブフォルダーに必須ライブラリーをコピー」を選択して実行可能Jarを作成するとJarファイルの中は次の構造となります。

Hello.jar
  |- META-INF
      |- MANIFEST.MF
  |- Hello.class

必須ライブラリーは、Hello_libというフォルダーが作成されサブフォルダーに配置されます。

Hello.jar
Hello_lib
  |- dsapi,jar
  |- jdom-1.1.3.jar

MANIFEST.MFの中は次のような構成。

Manifest-Version: 1.0
Class-Path: . Hello_lib/dsapi.jar Hello_lib/jdom-1.1.3.jar
Main-Class: Hello

まとめ

必須ライブラリをJarファイルに含める場合、Main-ClassがJarRsrcLoaderになり動作が変わる。