- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!Jarのマニフェストをいじる
マニフェスト中の、特定のキーの値が欲しいとき
Manifest manifest = jf.getManifest();
Attributes ma = manifest.getMainAttributes();
String classpath = (String)(ma.getValue("Class-Path"));
!COINSを実行可能JARから利用する
実行可能なJarファイルでは、manifestのClass-Pathで必要なライブラリへの
パスを通すことができる。
したがって、[COINS|http://www.coins-project.org/]を自分でつくったアプリケーションから使う場合、
[COINS|http://www.coins-project.org/]をビルドしてjarにしたファイル
([COINS|http://www.coins-project.org/]で配布されているjarではなくてclassesの下だけをjarにしたもの)
に対して、manifestでclass-pathを指定すればよいはずである。
が、Unix系(Linux、FreeBSD、MacOSX)ではうまく動かなかった。
# なぜかWindowsXPではうまく動いた。
これは、manifestの中のClass-PathがJavaのプロパティであるjava.class.pathに
含まれないために、COINSの中でクラスを動的にロードしようとしても
当該クラスをみつけることができないことに起因していた。
というわけで、これを回避するために、ちょっとハックしてみた。
{{ref coins-1.4.2.2-ja-searchClass_resursive.patch}}
COINSのディレクトリの中で、
patch -p0 < coins-1.4.2.2-ja-searchClass_resursive.patch
とすれば適用できる。
!COINSを実行可能JARから利用するための作業工程
たとえば、
wallet.jar
lib/coins.jar
というようなディレクトリ構成にしていて
wallet.jarは実行可能jarファイルで、manifestファイルで次のように
Manifest-Version: 1.0
Main-Class: net.wasamon.mics.Mics
Main-Class: net.wasamon.wallet.WalletGUI
Class-Path: lib/coins.jar
Class-Pathにlib/coins.jarをちゃんと指定していても
java -jar wallet.jar
としてLinuxやFreeBD、MacOSXで起動しようとすると
次のような例外が発生して実行できない。
ちなみにWindowsでダブルクリックするとなぜか実行できる。
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: coins.driver.SuffixFactory
at coins.driver.CompilerDriver.initializeSuffixFactory(CompilerDriver.java:81)
at coins.driver.CompilerDriver.<init>(CompilerDriver.java:184)
at net.wasamon.wallet.WalletDriver.doCompile(WalletDriver.java:156)
at net.wasamon.wallet.WalletGUI.actionPerformed(WalletGUI.java:204)
ちなみに、
java -cp wallet.jar:lib/coins.jar net.wasamon.wallet.WalletGUI
とした場合には、ちゃんと実行できる。
もちろん、coins.driver.SuffixFactoryはcoins.jarに含まれている。
で、みてみると、coins.driver.CompilerDriver.initializeSuffixFactoryで
getAttachedFileInputStream(Class String)という関数を呼び出していて、
このメソッドが原因となる例外を発生している。
このメソッドでは、
System.getProperty("java.class.path")で得られる
パスから、該当するクラスを検索するために
ディレクトリあるいは、jarファイルであっても求めるクラスを探す
searchClassメソッドを呼び出し、この戻り値が全て偽の場合に、例外が投げられる。
ここで問題となるのは、
java -jar wallet.jar
として起動した場合には、System.getProperty("java.class.path")で得られるのが
wallet.jarだけであるということ。
たしかに、これじゃあ、coins.jarの方は検索していないわけだから見つかるはずもない。
なのでmanifestで指定したClass-Pathファイルについても検索してもらう必要がある。
たとえば、こんな感じ。
Manifest manifest = jf.getManifest();
Attributes ma = manifest.getMainAttributes();
String classpath = (String)(ma.getValue("Class-Path"));
Attrubutesには、get(Object)というメソッドもあるが、getValue(String)でないとダメ。
で後は、ここで得られたclasspathを空白で分割して、
それぞれについて再帰的にsearchClassを検索すればいい。
幅優先で探索するべきなのかもしれないけど、まあ、とりあえず深さ優先で。
ちなみに、オリジナルのsearchClassは、真偽値を返すメソッドだが、
これでは、新しくmanifest中のClass-Pathから得たパスを返すことができないので、
真の代わりにパスを文字列で返し、偽の場合はnullを返すようにした。
{{category Java}}
{{category COINS}}