JDKのJavascript(nashron)で外部のJavaクラスを呼び出す方法
自分が作ったクラスや外部のライブラリを呼び出して、
機能を作りたい時があります。
普通にJavaで作ってもいいですが、
コンパイルが必要ですし、
早く作りたいのにJavaの厳格な文法がちょっと面倒です。
ScalaやGroovyなどを使って
軽くスクリプトを作るのもいいですが、
JDKに標準で入っていないから、やはり面倒。
それでJDK(バージョン8)に標準で入っているJavascriptエンジンnashronを
使ってみました。
しかし、nashronはなかなか外部クラスを認識してくれませんでした。
jrunscriptコマンド(またはjjsコマンド)の実行時に
−classpathや-cpにクラスパスをjavaコマンドと同じ方法で指定したのにも関わらず、
いつもClassNotFoundExceptionが発生して困っていました。
色々と試した結果、やっと外部のJavaクラスを認識してくれたので、その方法をメモします。
まず、jrunscriptの実行時に以下のようにクラスパスを指定します。
Linux(Ubuntu)を基準に説明します。
例えば、/dukelab/libに10個のjarファイルがあって、それらをjrunscriptにクラスパスとして通したいなら、以下のように起動します。
jrunscript -cp `echo /dukelab/lib/* | tr ' ' ':'`
ちょっと複雑で、これ以外の方法もあると思いますが、
今のところ、これで行けました。
単純にjrunscript -cp /dukelab/lib/*とすると、うまく行きません。
Linuxのシェルで"/dukelab/lib/*"が式として評価されて、
jrunscript -cp /dukelab/lib/a.jar /dukelab/lib/b.jar... のように
展開されて実行されます。
コマンドプロンプトでは空白文字で引数を分離していますから、
/dukelab/lib/b.jarがスクリプトファイルとして認識され、jrunscriptが実行されます。
当然/dukelab/lib/b.jarはスクリプトと関係ないバイナリのファイルですから、エラーになってしまいます。
それで上記の`echo /dukelab/lib/* | tr ' ' ':'`のように/dukelab/lib/*の展開後に、
trコマンドで空白文字をクラスパスの区切り文字である:に変換する処理を追加しました。
こうすると、実際には
jrunscript -cp /dukelab/lib/a.jar:/dukelab/lib/b.jar...
のようになるので、クラスパスとしてうまく認識できるようになります。
もし、jarファイルでなく、classファイルが置かれているディレクトリなら、もっと簡単です。
例えば、/dukelab/classes配下にJavaクラスがあるなら、
以下のように指定します。
jrunscript -cp /dukelab/classes
クラスパスを複数指定する時は:(コロン。Windowsでは;(セミコロン))で区切って下さい。
これで準備が終わり、Javascriptの話になりますが、
dukelab.js.test1パッケージにあるTestOneクラスと
dukelab.js.test2パッケージにあるTestTwoクラスをJavascriptで呼び出してみます。
2つのクラスはSystem.out.printlnを呼び出すごく単純なクラスなので、内容は割愛します。
var pkgs = new JavaImporter( Packages.dukelab.js.test1, Packages.dukelab.js.test2 ); with(pkgs) { print("TestOne : " + TestOne.getString()); print("TestTwo : " + TestTwo.getInt()); }
実行すると、以下のように表示されます。
TestOne : wow! TestTwo : great!
つまりいうと、Packagesオブジェクトの次に使うJavaクラスの完全修飾名を指定して呼び出すということです。
ただ、いつもPackages.dukelab.js.test1.TestOne.getString()...ように呼び出すのは辛いから
上記のようにwith文を使ってパッケージを省略して使うのがいいでしょう。
with文はJavascriptではスコープが曖昧になってしまうため、使わない方がいいと言われていますが、
JavascriptでJavaクラスを使う時は便宜上、必須ではないかと思います。
ということで少なくともJavaの中のJavascriptでは、with文は当分健在だろうと勝手に思っています。
そのうち、新しい文法ができるかもしれませんが...
最後にJavascriptにおけるJavaクラスの呼出方法をまとめておきます。
// 完全修飾名で呼出し print(Packages.dukelab.js.test1.TestOne.getString()); // with文でパッケージ(一つ)を省略 with (Packages.dukelab.js.test1) { print(TestOne.getString()); } // with文でパッケージ(一つ以上)を省略 with (new JavaImporter(Packages.dukelab.js.test1, Packages.dukelab.js.test2)) { print(TestOne.getString()); print(TestTwo.getInt()); }