!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.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.(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}}