JDK 8 build b91 を使って JavaScript から JavaFX の WebView をいじる
JDK 8 と JavaFX と Nashorn
OpenJDK のページを見ていると、JDK 8 のマイルストーンとして 5 月 23 日に Feature Complete とあった。
というわけで 5 月 23 日にリリースされた JDK 8 build b91 に一通りの機能が詰まってるものだと思って *1、主に JavaFX とか Nashorn とかを試してみた。
JavaFX 2
クライアントサイドの GUI プラットフォーム (?)。 JDK 7 の途中から標準で JDK に含まれるようになった。 JavaFX 1.x 系はあんまり使われてなかった印象があるけど、JavaFX 2.x 系になってからは実態もガラッと変わり、Swing を置きかえて今後の Java の GUI プログラミングの主流になるっぽい。
JavaFX には WebView があって、ページ中の DOM オブジェクトに Java 側から触れるというあたりが web 系の開発者としては興味深いところ。 JDK 8 build b91 にも含まれている。
JavaScript 処理エンジン Nashorn
Java で書かれた JavaScript 処理エンジン。 JDK 8 以降に標準で含まれる。
もともと Java の JavaScript 処理系といえば Mozilla 製品の Rhino があったわけで、JDK 6 以降には Rhino が標準で含まれていたのだけれど、JDK 8 以降ではこれが Nashorn で置きかえられる。 JDK 8 build b91 にも含まれている。
(Rhino のときからそうだけど) JavaScript から Java のライブラリを (少ない障壁で) 触れるというのが使いやすくて好き。
JDK 8 Early Access Releases のインストール
Early Access Releases として JDK 8 のページでダウンロードできるようになっている。 5 月 23 日には build b91 がリリースされている。
ダウンロードして展開してパスを通せば使えるはず *3。
jjs コマンドで JavaScript を実行する
コマンドラインツールとして jjs コマンドが含まれている。 このコマンドにファイルパスを渡すとそのファイルを JavaScript として実行できる。 また、ファイルパスを渡さなければ対話型の JS 処理系が開始される (Ruby における irb みたいなもの)。
当然ながら Java の入出力機能が使えるので “Hello world!” の出力は以下のようになる。
java.lang.System.out.println("Hello world!");
まあ print
関数を使った方が短くなるけど。
print("Hello world!");
みんな大好き public static void main
を書かなくても実行できちゃうのは寂しいところ。
jjs コマンドで JavaFX アプリケーションを実行する
最近 (?) jjs コマンドに -fx オプションが追加されたらしい。 詳細は下記ブログ記事に書かれている。
jjs コマンドで -fx オプションを使うと、JavaScript で簡単に JavaFX アプリケーションを書くことができる。
// Java の import 文の代わりにこんな感じに書ける var StackPane = javafx.scene.layout.StackPane; var Scene = javafx.scene.Scene; var Label = javafx.scene.control.Label; var Screen = javafx.stage.Screen; function start(stage) { stage.title = "Hello World!"; var label = new Label("Hello world!"); var root = new StackPane(); root.getChildren().add(label); var scene = new Scene(root, 300, 200); stage.setScene(scene); stage.show(); }
上のコードを helloworld.js というファイル名で保存しておいて、
jjs -fx helloworld.js
という感じで jjs コマンドを実行すれば、次のようなウィンドウが表示されるはず。
ちょっとした GUI アプリケーションを書くときに便利かも?
JavaFX の WebView と WebEngine を使う
ここからが本題。 上にも書いたように、JavaFX には WebView や WebEngine といったものが含まれている。
これらを使えば、指定の web ページを WebEngine に読み込ませて、その DOM に Java から触ることができる。 もちろん Nashorn を使えば JavaScript から Java に触れるわけなので、JavaScript から読み込んだページの DOM とかを触れるわけだ。
例えばこのブログの全リンク (anchor 要素) のテキストと href 属性を取得して表示するプログラムは次のようになる。
var Scene = javafx.scene.Scene; var WebView = javafx.scene.web.WebView; function start(stage) { var view = new WebView(); var webEngine = view.getEngine(); webEngine.load("http://vividcode.hatenablog.com/"); // 読み込み完了時の処理 webEngine.getLoadWorker().stateProperty().addListener( // Java の匿名内部クラス的な構文 // 他の書き方があるかもしれないけどよく知らない new javafx.beans.value.ChangeListener() { changed: function (ov, oldState, newState) { if (newState === javafx.concurrent.Worker.State.SUCCEEDED) { stage.setTitle(webEngine.getLocation()); printAllAnchorElemsFromDoc(webEngine.getDocument()); exit(); // 本当は何か終了処理を入れないとダメかもしれない } } } ); stage.setScene(new Scene(view, 800, 600)); stage.show(); } function printAllAnchorElemsFromDoc(doc) { var elems = doc.querySelectorAll("a"); for (var i = 0; i < elems.length; ++i) { var elem = elems[i]; var caption = elem.textContent; if (caption === null) caption = ""; caption = caption.trim().replaceAll(/\s+/g, " "); var link = elem.getAttribute("href"); //表示 java.lang.System.out.printf("%s%n → %s%n", caption, link); } }
もちろん Java だけでも同様のことはできるわけだけど、ちょっとした処理なら JS でぱぱっと書けるのは便利だと思う。
(追記) 別に表示させる必要がないなら WebEngine だけ使えばよくて WebView を使う必要はない。
あなたと Nashorn、今すぐダウンロード
最近はコマンドラインで JS を処理させる方法として Node.js が主流という感じではありますが、次のような方には Nashorn がおすすめです!!!
- Java が好きすぎて JavaScript を書いているときも Java の存在を感じていたい方
- Java と JavaScript の違いがわからない方