【问题标题】:Injected members from the host language to arrive to guest language as guest language types将成员从宿主语言注入到访客语言作为访客语言类型
【发布时间】:2018-08-06 11:54:10
【问题描述】:

这个问题有点相关: GraalVM - Using Polyglot Value without a context

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

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

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

guestLanguageBindings.putMember(argumentName, argumentValue);

以 JS 数组的形式“到达”来宾语言,而不是现在发生的 java.util.ArrayList。

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

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

谢谢!

【问题讨论】:

    标签: graalvm


    【解决方案1】:

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

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

    【讨论】:

    • 抱歉一段时间后才发布澄清。我已更新我的代码以使用 ProxyArray.fromArray()。但是在 JS 端(客户语言)中,数组不被视为 JS 数组,而是类型:org.graalvm.polyglot.proxy.ProxyArray(也是 Java 类型)。这意味着不能像使用常规 JS 数组一样使用该数组。像 arr[0] 之类的语句(例如在您的示例中)有效,但是诸如 arr.sort() 之类的特定调用失败。我希望该数组可以像 JS 数组一样在来宾端使用。这不可能吗?
    • 感谢您的反馈。理想情况下,js 内置只适用于 ProxyArray 等互操作类型。但是 graal.js 的覆盖范围还不够完整。如果您可以向github.com/graalvm/graaljs/issues 报告错误,那就太好了。
    • 您好,感谢您回复我。当然,我会提交一个错误报告。您能否详细说明一下:“理想情况下,js 内置函数仅适用于 ProxyArray 等互操作类型。” 不确定我是否完全理解您的意思。
    • 仅供参考,这是我的错误报告以及附加信息:github.com/graalvm/graaljs/issues/45
    【解决方案2】:

    @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);");
    

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

    【讨论】:

      猜你喜欢
      • 2019-11-12
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多