以下の情報を提供してださった方ありがとうございました。 いろいろ検証してみた結果、APIを別途用意しないと解決できない問題のようなのでメモを残しておきます。
Java+Swingによる2chブラウザ V2C_R76c2ch.net//【コマンド】${SCRIPT:A} test.js var frame = new javax.swing.JFrame('テスト'); frame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(new java.awt.Dimension(200, 100)); frame.setLayout(new java.awt.BorderLayout()); frame.add(mp()); frame.show(); function mp() { var p = new javax.swing.JPanel(); var b = new javax.swing.JButton("OK"); b.addActionListener(function(e) { var fc = new javax.swing.JFileChooser(); fc.showOpenDialog(null); }); p.add(b); return p; }
このスクリプトはV2C-RのRhinoでは実行できますが、Nashornでは実行できません。
Nashornでは
var fc = new javax.swing.JFileChooser();
の行が内部でSystem.getProperty("os.name")を呼んでいて、そこでパーミッションエラーが起きます。
コマンドに「A」パーミッション指定を行っているのでエラーにはならないはずですが、Nashornではスクリプトがバイトコード に変換されているせいか、ボタンのリスナー実行時にはスクリプトのコンテキストからV2Cの実行コンテキストに戻ってしまっていることが 原因のようです。V2Cは常に最小に制限されたアクセスコントロールコンテキストで動いているようです。
上のスクリプトでは
var fc = new javax.swing.JFileChooser();
の行をb.addActionListenerの前に実行しておけばエラーが起きずに実行できますが、
それでは根本的な解決にはなっていません。
いろいろ試してみましたが、V2C-Rの本体側だけではコンテキストを維持する方法、またはコンテキストが外れる処理をフックする方法が見つかりませんでした。ほかにもっとうまい方法があるのかもしれませんが暫定的な対処方法として、
新たにv2cオブジェクトにメソッドを追加します。
v2c.invokeMethod(obj, funcName, param)・・・スクリプト上のオブジェクトobjに対し、funcNameメソッドを呼び出します;
このメソッドはパーミッションを設定しなおしたコンテキストで実行されるので上記の問題を解決するために使うことができます。
イベントハンドラ内で直接v2c.invokeMethodを呼び出してもいいのですが、本家のV2CとV2C-R、さらにJava7とJava8以降を同時にサポートするために、
以下のような関数をスクリプト内で定義すると見通しがよくなると思います。
function invoke(func, param) { if (v2c.invokeMethod) { v2c.invokeMethod({run:func}, "run", param); } else { func(param); } }
この関数を用いて先程の例を書き直すと以下のようになります。
//【コマンド】${SCRIPT:A} test.js var frame = new javax.swing.JFrame('テスト'); frame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(new java.awt.Dimension(200, 100)); frame.setLayout(new java.awt.BorderLayout()); frame.add(mp()); frame.show(); function mp() { var p = new javax.swing.JPanel(); var b = new javax.swing.JButton("OK"); b.addActionListener(function(e) { invoke(function() { var fc = new javax.swing.JFileChooser(); fc.showOpenDialog(null); }); }); p.add(b); return p; } function invoke(func, param) { if (v2c.invokeMethod) { v2c.invokeMethod({run:func}, "run", param); } else { func(param); } }
invoke関数を用いる場合にはfunc内のthisが指すオブジェクトが変わることに注意しなければいけないかもしれません。