2

这个问题有点相关: 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 并转换回来宾语言来解决这个问题。

这可行,但我想知道是否有更合适的方法来做到这一点,或者是否确实使用绑定是正确的方法?

谢谢!

4

2 回答 2

5

这可行,但我想知道是否有更合适的方法来做到这一点,或者是否确实使用绑定是正确的方法?

正如您所注意到的,当您将 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

于 2018-08-06T12:32:34.103 回答
0

@Christian Humer 提供的建议使用 ProxyArray 的答案是一个很好的答案,并且是关于如何组合 ProxyArray 的解释是正确且很好的呈现。

但是,我的要求是能够呈现数组参数(使用顶级绑定设置),就好像它是来宾语言数据类型一样。ProxyArray 只能让我走到一半,结果数据类型是 Java 类型,而不是 JS 类型。

为了完全实现上述目标,由于我在控制 Java 主机端,因此我在主机端使用 Context 预先创建了一个 JS 数组,并将 Java ArrayList 的内容复制到其中。在调用guest代码的时候,我只是简单的在bindings中设置了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);");

当我提交上述评论中提到的错误报告时,我在 Github 上向我建议了这种方法。

于 2018-08-28T06:56:03.197 回答