将 toString 方法暴露给 nashorn 中的 js 对象
expose toString method to js objects in nashorn
可能是个愚蠢的问题,但我找不到任何关于它的直接文档,所以在这里。
我想向 JS 端公开一个 Java "constructor",在实例化时它应该创建一个带有 "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();")
}
}
你可以这样试试:
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);
}
}
如果您实现 JSObject,nashorn 将路由所有 property/index 访问,通过 JSObject 方法调用,如 getMember、getSlot、setMember、setSlot、调用方法。我稍微修改了您的代码以将 "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());");
}
}
可能是个愚蠢的问题,但我找不到任何关于它的直接文档,所以在这里。
我想向 JS 端公开一个 Java "constructor",在实例化时它应该创建一个带有 "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();")
}
}
你可以这样试试:
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);
}
}
如果您实现 JSObject,nashorn 将路由所有 property/index 访问,通过 JSObject 方法调用,如 getMember、getSlot、setMember、setSlot、调用方法。我稍微修改了您的代码以将 "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());");
}
}