将toString方法暴露给nashorn中的js对象

时间:2016-05-11 23:51:56

标签: javascript java nashorn

潜在的愚蠢问题,但我找不到任何关于它的直接文档,所以在这里。

我想公开一个Java"构造函数"对于JS方面,在实例化时,它应该创建一个带有" toString"的实例。方法就可以了。

// java class
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import jdk.nashorn.api.scripting.AbstractJSObject;

public class Foo extends AbstractJSObject {
    String bar;

    public Foo() {
        super();
    }

    public Foo(String b) {
        super();
        this.bar = b;
    }

    @Override
    public Object newObject(Object... args) {
         String bar = null;
        if (args[0] != null) bar = args[0].toString();

        Foo f = new Foo(bar);
        return f;
    }

    @Override
    public String toString() {
        return "Foo: " + this.bar;
    }


    public static void main(String[] args) {
        ScriptEngine engine = new  ScriptEngineManager().getEngineByName("nashorn");
        engine.put("foo", new Foo());

        // f.toString however is null
        engine.eval("var f = new foo('hi'); f.toString();")
    }
}

2 个答案:

答案 0 :(得分:2)

如果实现JSObject,nashorn将路由所有属性/索引访问,通过JSObject方法调用,如getMember,getSlot,setMember,setSlot,call方法。我稍微修改了你的代码,将“toString”暴露为你的Foo对象的属性,并使其可编辑和可运行的代码:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import jdk.nashorn.api.scripting.AbstractJSObject;
import java.util.function.Supplier;

public class Foo extends AbstractJSObject {
    String bar;

    public Foo() {
        super();
    }

    public Foo(String b) {
        super();
        this.bar = b;
    }

    @Override
    public Object newObject(Object... args) {
        String bar = null;
        if (args[0] != null) bar = args[0].toString();

        Foo f = new Foo(bar);
        return f;
    }

    @Override
    public Object getMember(String name) {
        if (name.equals("toString")) {
            // Returning a lambda function as value of this property.
            // nashorn code can call lambdas just like script functions!
            // You may also choose to return another JSObject that
            // returns true in isFunction() method and implements "call"
            // as well.

            return (Supplier<String>)this::toString;
        } else {
            // implement other exposed properties here.
            return null;
        }
    }

    @Override
    public String toString() {
        return "Foo: " + this.bar;
    }


    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new  ScriptEngineManager().getEngineByName("nashorn");
        engine.put("foo", new Foo());

        // f.toString() would call getMember("toString") and the
        // returning lambda is called!

        engine.eval("var f = new foo('hi'); print(f.toString());");
    }
}

答案 1 :(得分:0)

您可以尝试这种方式:

import javax.script.*;

    import jdk.nashorn.api.scripting.AbstractJSObject;

    public class Foo extends AbstractJSObject {
        String bar;

        public Foo() {
            super();
        }

        public Foo(String b) {
            super();
            this.bar = b;
        }

        @Override
        public Object newObject(Object... args) {
            String bar = null;
            if (args[0] != null) bar = args[0].toString();

            Foo f = new Foo(bar);
            return f;
        }

        @Override
        public String toString() {
            return "Foo: " + this.bar;
        }


        public static void main(String[] args) throws ScriptException {
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
            engine.put("foo", new Foo());

            Compilable compilable = (Compilable) engine;
            Bindings bindings = engine.createBindings();
            String script = "function add(op1,op2){return op1+op2} add(a, b)";
            CompiledScript jsFunction = compilable.compile(script);
            bindings.put("a", 1);bindings.put("b", 2); //put java object into js runtime environment
            Object result = jsFunction.eval(bindings);
            System.out.println(result);
        }
    }