今更な話題ですが 将来 nashorn (JEP 335: Deprecate the Nashorn JavaScript Engine ) が廃止になるらしい.
nashorn の代わりに Rhino で実行する方法を調査したのでメモします.
MDN web docs Tutorial: Embedding Rhino を読めばだいたいわかります。
Java側でJavaScriptで使うことを想定して用意したオブジェクトは JavaScript host objects とよばれているようです.
ここでは JavaScript から使う Pikachu オブジェクトを Java側で用意する例を考えます. pikachu.say
すると pika と発言するようにしましょう.
Java 側( コードは Groovy ) で用意します.
public class Pikachu extends ScriptableObject {
@Override
String getClassName() { return 'Pikachu' }
Pikachu(){}
@JSFunction
String sayHello(int i){ return 'pika ' * i }
}
これを使うコード:
def cx = Context.enter()
def scope = cx.initStandardObjects()
ScriptableObject.defineClass(scope, Pikachu.class)
で用意しておき:
def result = cx.evaluateString(scope, 'new Pikachu().sayHello(1);', "<cmd>", 1, null)
で JavaScript new Pickachu().sayHello(1); を評価します. result には pika が入ります.
コード全体では以下のようになります.
pikachu.groovy
@Grab(group='org.mozilla', module='rhino', version='1.7.12')
import org.mozilla.javascript.Context
import org.mozilla.javascript.ScriptableObject
import org.mozilla.javascript.annotations.JSFunction
public class Pikachu extends ScriptableObject {
@Override
String getClassName() { return 'Pikachu' }
Pikachu(){}
@JSFunction
String sayHello(int i){ return 'pika ' * i }
}
def cx = Context.enter()
def scope = cx.initStandardObjects()
ScriptableObject.defineClass(scope, Pikachu.class)
def script0 = 'new Pikachu().sayHello(3);'
def result0 = cx.evaluateString(scope, script0, "<cmd>", 1, null)
println result0
Context.exit()
groovy pikachu して実行:
$ groovy pikachu
pika pika pika
になります.
あらかじめ、Pikachu クラスのインスタンス pikachu を グローバルスコープに存在させておくようにするには、Java側で以下の記述を追加しておけばOKです.
def pikachu = cx.newObject(scope, "Pikachu")
scope.put("pikachu", scope, pikachu)
これなら javascript 側は:
pikachu.sayHello(3);
だけになります。
see also : Rhino で実行する javascript をコンパイルしてから使う