该问题与以下内容有关: GraalVM - Using Polyglot Value without a context
在我的应用程序中,以来宾语言运行的代码片段不需要知道注入的参数(通过绑定的成员)是Java参数。相反,对于使用来宾语言开发的人,参数应该看起来像来宾语言本身的另一个参数。
例如,我希望以这种方式从Java宿主语言向JS来宾脚本中注入一个数组:
Value guestLanguageBindings = context.getBindings(scriptData.getLanguage().toString());
guestLanguageBindings.putMember(argumentName, argumentValue);
作为JS数组“到达”来宾语言,而不是作为java.util.ArrayList来“到达”来宾语言。
当前,我通过将每个非原始类型(我注意到String,int等作为JS“类型”到达JS)转换为JSON并转换为来宾语言来解决此问题。
这行得通,但是我想知道是否有更合适的方法来做,或者确实使用绑定是正确的方法?
谢谢!
答案 0 :(得分:4)
这行得通,但是我想知道是否有更合适的方法来做,或者确实使用绑定是正确的方法?
正如您所注意到的,当您将Java对象放入多语言时,对于用户而言,它们将看起来像Java对象,而不是JavaScript对象。为了使它们模仿来宾语言对象,您可以使用Polyglot Proxy API。
JS对象的示例(由HashMap支持)
try (Context context = Context.create("js")) {
Map<String, Object> backingMap = new HashMap<>();
backingMap.put("foo", "bar");
context.getBindings("js").putMember("hostObject", ProxyObject.fromMap(backingMap));
assert "bar".equals(context.eval("js", "hostObject.foo").asString());
backingMap.put("foo", "baz");
assert "baz".equals(context.eval("js", "hostObject.foo").asString());
}
JS数组示例(由Java数组支持):
try (Context context = Context.create("js")) {
Object[] backingArray = new Object[42];
backingArray[0] = 42;
context.getBindings("js").putMember("hostObject", ProxyArray.fromArray(backingArray));
assert 42 == context.eval("js", "hostObject[0]").asInt();
backingArray[0] = 43;
assert 43 == context.eval("js", "hostObject[0]").asInt();
}
函数示例(由Lambda支持)
try (Context context = Context.create("js")) {
ProxyExecutable executable = (arguments) -> arguments[0];
context.getBindings("js").putMember("hostObject",executable);
assert 42 == context.eval("js", "hostObject(42)").asInt();
assert 43 == context.eval("js", "hostObject(43)").asInt();
}
您还可以直接实现ProxyObject和ProxyArray来自定义行为,例如如果要提供只读对象或数组。
这是另一个代理示例:http://www.graalvm.org/docs/graalvm-as-a-platform/embed/#computed-arrays-using-polyglot-proxies
代理Javadoc:http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/proxy/package-summary.html
答案 1 :(得分:0)
@Christian Humer提供的答案表明使用ProxyArray是一个很好的答案,它说明了如何正确组合ProxyArray并给出了很好的解释。
但是,我的要求是要能够将数组参数(使用顶级绑定设置)呈现为一种来宾语言数据类型。 ProxyArray仅使我半途而废,结果数据类型是Java类型,而不是JS类型。
为了完全实现上述目标,由于我控制着Java主机端,因此我在主机端使用Context创建了一个JS数组,并在其中复制了Java ArrayList的内容。 。调用访客代码时,我只需在绑定中设置JS数组,该绑定已经是功能齐全的JS数组。
Value jsArray = context.eval("js", "new Array();");
jsArray.setArrayElement(0, 1001); //array will grow automatically, JS semantics
jsArray.setArrayElement(1, 1002);
jsArray.setArrayElement(2, 1003);
guestLanguageBindings.putMember("variable", jsArray);
context.eval("js", "print(variable);");
当我提交上述评论中提到的错误报告时,向我on Github建议了这种方法。