Java から evaluateString する形で javascript コードを実行する場合に Node.js のように console.log() したい、という場合の解決方法.
scope に Global を使うと print ファンクションがトップレベルに存在するようになる.
@Grab(group='org.mozilla', module='rhino', version='1.7.12')
import org.mozilla.javascript.Context
import org.mozilla.javascript.tools.shell.Global
def script0 = 'print("hello world!");'
def cx = Context.enter()
def global = new Global(cx)
cx.evaluateString(global, script0, "<cmd>", 1, null)
Context.exit()
print の代わりに console.log が使いたければ、 javascript コードの先頭に以下を追記:
var console = {};
console.log = function(msg){ print(msg); };
console.log("hello world!");
Console という ScriptableObject を自分でつくって解決する:
class Console extends ScriptableObject {
@Override
String getClassName() { return "Console" }
Console(){}
@JSFunction
void log(String msg){
System.out.println(msg)
}
}
このクラスを console という名前で 現在の scope に存在させる:
ScriptableObject.defineClass(scope, Console.class)
def console = cx.newObject(scope, "Console")
ScriptableObject.putProperty(scope, "console", console)
コード全体:
@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
class Console extends ScriptableObject {
@Override
String getClassName() { return "Console" }
Console(){}
@JSFunction
void log(String msg){
System.out.println(msg)
}
}
def script0 = 'console.log("hello world!");'
def cx = Context.enter()
def scope = cx.initStandardObjects()
ScriptableObject.defineClass(scope, Console.class)
def console = cx.newObject(scope, "Console")
ScriptableObject.putProperty(scope, "console", console)
cx.evaluateString(scope, script0, "<cmd>", 1, null)
Context.exit()
Javaの System.out を out という名前でグローバルに存在するようにする:
def jsOut = Context.javaToJS(System.out, scope)
ScriptableObject.putProperty(scope, "out", jsOut)
ちょっとデバッグするだけの目的ならば 解決策 C がいいかな。