从宿主语言注入成员以作为访客语言类型到达访客语言

Injected members from the host language to arrive to guest language as guest language types

这个问题有点相关:

在我的应用程序中,来宾语言中的代码片段 运行 不需要知道注入的参数(通过绑定成员)是 Java 个参数。相反,对于使用来宾语言开发的人来说,参数应该看起来只是来宾语言本身的另一个参数。

例如,我想要一个从我的 Java 宿主语言注入到 JS 来宾脚本的数组,以这种方式:

Value guestLanguageBindings = context.getBindings(scriptData.getLanguage().toString());

guestLanguageBindings.putMember(argumentName, argumentValue);

到 "arrive" 到访客语言作为 JS 数组,而不是现在正在发生的 java.util.ArrayList。

目前,我通过将每个非原始类型(我注意到 String、int 等作为 JS "types" 到达 JS)转换为 JSON 并在来宾中转换回来解决这个问题语。

这行得通,但我想知道是否有更合适的方法,或者使用绑定是否确实是正确的方法?

谢谢!

This works, but I wonder if there is a more appropriate way to do it or if indeed using the bindings is the right way to go?

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

代理 Java文档:http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/proxy/package-summary.html

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

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

为了完全实现上述目标,因为我控制着 Java 主机端,所以我在主机端使用上下文预先创建了一个 JS 数组,并复制了内容其中的 Java ArrayList。在调用访客代码时,我只是简单地在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);");

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