JavaFX の eval を試してみる
JavaScript の (EcmaScript の) eval() 関数に似た JavaFX の javafx.util.FXEvaluator を試してみます。
Java SE 6 Update 11 と JavaFX SDK 1.1 を使います。
ところで JavaScript の eval() 関数というのは文字列として与えられた JavaScript の式を評価して実行してくれる関数のことです。eval - Wikipedia
使い方はとても簡単です。次のようなプログラムを書いてみます。
package fooami; import javafx.util.FXEvaluator; /** * FXEvaluator の勉強です。 * @author hide1080 */ function run(args: String[]) { FXEvaluator.eval(args[0]); }
ここではあえて引数のチェックなどは省略してます。プログラムによってはしっかりチェックすべきかもしれません。
これをコンパイルします。
C:\WORK\fx>javafxc fooami\EvalExample.fx C:\WORK\fx>
コンパイルできました。
それでは試してみます。
C:\WORK\fx>javafx fooami.EvalExample "println('Hello')" java.lang.RuntimeException: javax.script.ScriptException: no scripting engine available at javafx.util.FXEvaluator.eval(FXEvaluator.java:80) at fooami.EvalExample.javafx$run$(EvalExample.fx:11) Caused by: javax.script.ScriptException: no scripting engine available at javafx.util.Evaluator.eval(FXEvaluator.java:39) at javafx.util.FXEvaluator.eval(FXEvaluator.java:78) at fooami.EvalExample.javafx$run$(EvalExample.fx:11) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.sun.javafx.runtime.provider.AWT_EDT_RuntimeProvider$1.run(AWT_EDT_RuntimeProvider.java:104) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) C:\WORK\fx>
うおっと><
「no scripting engine available」と言われてしまいました。必要なライブラリを CLASSPATH に設定する必要があります。
[JavaFX SDK インストールフォルダ]\lib\shared\javafxc.jar を CLASSPATH に設定したら、気を取り直して再度実行してみます。
C:\WORK\fx>set classpath=%classpath%;C:\TOOLS\javafx\javafx-sdk1.1\lib\shared\javafxc.jar C:\WORK\fx>javafx fooami.EvalExample "println('Hello')" Hello C:\WORK\fx>
出ました!
それではいろいろと試してみます。
C:\WORK\fx>javafx fooami.EvalExample "var a = 1 + 2; println(a)" 3 C:\WORK\fx>
ふむふむ。
更に試してみます。
※ここでは見やすさを考えて適当な位置で改行してますが実際には一行のコマンドとして実行してます。
C:\WORK\fx>javafx fooami.EvalExample "function add(a:Integer, b:Integer) :Integer{a+b} println(add(5, 10))" 15 C:\WORK\fx>
ふんふん。
最後に以下のプログラムを一行に繋げた文字列を渡してみます。
import javafx.scene.text.Text; import javafx.scene.Scene; import javafx.stage.Stage; Stage { title: 'Evaluator Example' scene: Scene { width: 220.0 height: 100.0 content: Text { x: 15.0 y: 50.0 content: 'I love Java, JavaScript, and JavaFX!' } } }
※ここでは見やすさを考えて適当な位置で改行してますが実際には一行のコマンドとして実行してます。
C:\WORK\fx>javafx fooami.EvalExample "import javafx.scene.text.Text; import javafx.scene.Scene; import javafx.stage.Stage; Stage{ title: 'Evaluator Example' scene: Scene{width: 220.0 height: 100.0 content: Text{x: 15.0 y: 50.0 content: 'I love Java, JavaScript, and JavaFX!' }}}"
さてさて、今回試した JavaFX 版 eval() の javafx.util.FXEvaluator ですが、JavaFX にとってなかなか強力な道具として使えそうな気がしてます。
あくまでイメージですが アプレットとして動かせば JSObject から Web ページ上の JavaScript 関数を介して クロスドメインの Web API を呼び出して JSONP のようなメッセージを取得すれば Jar ファイルに署名することなく Java のセキュリティ制限にかからずに動的に振る舞いを変更できたりするのではないかな。。。と。
でもまあ、将来はアプレットと Java Web Start に対するネットワークのセキュリティ制限が緩くなるとかって話を、何処かで聞いたか読んだかした気もするので、そうなればこんなの何でもないテクニックになるかもしれないですが。
もう一つ将来の話ですが、次期 JavaFX のリリース (Marina) では read-eval-print-loop な機能が利用可能になるようです。(現在でも Mercurial repository からリソースを取得すれば今すぐ試せるようですが幾つかの問題が今後更に改善される予定だそうです)
他の read-eval-print-loop なものとしては、jrunscript や、Ruby の irb などがあります。Python も 対話モードを備えています。(Python は現在のんびり勉強中)
RIA な JavaFX と REPL なんて全然結びつかない気もしますが、とりあえず勉強は面白くできそうな気がします。使ってみれば意外な可能性が見えたりするのかもしれません。
とまあそんなわけで、今回は JavaFX の eval について試してみたよというお話でした。