Home About
javascript, rhino, groovy

Rhino で console.log() したい

Java から evaluateString する形で javascript コードを実行する場合に Node.js のように console.log() したい、という場合の解決方法.

解決策 A) Global を使って解決する

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!");

解決策 B) console オブジェクトを自分で用意して使う

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()

解決策 C) System.out を使う

Javaの System.out を out という名前でグローバルに存在するようにする:

def jsOut = Context.javaToJS(System.out, scope)
ScriptableObject.putProperty(scope, "out", jsOut)

まとめ

ちょっとデバッグするだけの目的ならば 解決策 C がいいかな。