【问题标题】:Java and Javascript bind function with arrays as parameter以数组为参数的 Java 和 Javascript 绑定函数
【发布时间】:2018-10-24 13:45:03
【问题描述】:

我正在努力实现以下目标。 Java 应用程序应该通过 ScriptEngineManager/ScriptEngine 运行 javascript,并且 javascript 应该能够从 Java 应用程序调用函数。只要只传入和传出一个简单的变量,这就会很好。但我无法让它传递数组。 这是我的代码:

private static class test implements Function<Integer[], Integer[]> {
    @Override
    public Integer[] apply(Integer[] msg) {
        for(int i = 0; i < msg.length; i++) System.out.println(msg[i]);     
        Integer[] a = {1, 2, 3};           
        return a;
    }
}

public static void main(String[] args) throws ScriptException {
    String ps = "var e = [0x04, 0x05, 0x06]; var a = send(e); for(i in a) print(i);";
    ScriptEngineManager sm = new ScriptEngineManager();
    ScriptEngine eng = sm.getEngineByName("JavaScript");
    Bindings mbind = eng.createBindings();
    mbind.put("send", new test());
    eng.setBindings(mbind, ScriptContext.ENGINE_SCOPE);
    Object t = eng.eval(ps);
}

我得到错误:

线程 "main" java.lang.ClassCastException 中的异常:jdk.nashorn.api.scripting.ScriptObjectMirror 无法转换为 [Ljava.lang.Integer; 在 scripttest$test.apply(scripttest.java:1) 在 jdk.nashorn.internal.scripts.Script$\^eval_.:program(:1) 在 jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637) 在 jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494) 在 jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) 在 jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:446) 在 jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:403) 在 jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399) 在 jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155) 在 javax.script.AbstractScriptEngine.eval(未知来源) 在 scripttest.main(scripttest.java:26)

有人知道如何传递数组吗?

谢谢! 问候

【问题讨论】:

  • 请注意,当您的 Javascript 尝试打印结果时,它实际上会遍历 a 的字段,而不是成员 - for(... in ...) 是遍历对象字段的语法,所以如果a 确实是一个 3 成员数组,无论数组的内容如何,​​输出都是 0\n1\n2\n。数组迭代的 Javascript 语法是 for(... of ...).

标签: javascript java scriptengine


【解决方案1】:

对数组的反射在 Java 中是一个小问题(原始类型和所有垃圾),所以 JSR-223 脚本引擎在处理它们时遇到了麻烦。我用新的 GraalVM 尝试了相同的代码,但遇到了同样的问题——引擎放弃了寻找一个好的映射,只是尝试提交它的数组值的本机表示(Nashorn 使用 ScriptObjectMirror 而 GraalVM 使用 @ 987654324@).

如果您希望您的主机函数看起来像是在接受“真实数组”(来宾数组的实现),您的主机函数将需要接受底层 ScriptEngine 的内部实现并学习对其进行操作.根据this SO answerScriptObjectMirror API docs,您应该可以使用obj.to(int[].class) 方法从代理对象中提取内部整数数组。

这种方法的主要缺点是您的主机函数必须支持您可能想要支持的每个特定ScriptEngines 的每个特定内部表示。

由于当前 JDK 不推荐使用 Nashorn Javascript 引擎,您可能还希望支持 GraalVM,以防您的实现可能如下所示:

private static class test implements Function<Object, Integer[]> {
    @Override
    public Integer[] apply(Object inp) {
        int[] msg;
        if (inp instanceof ScriptObjectMirror)
            msg = ((ScriptObjectMirror)inp).to(int[].class);
        else if (inp instanceof AbstractMap)
            msg = Value.asValue(inp).as(int[].class);
        else
            return null;
        for (int i = 0; i < msg.length; i++)
            System.out.println(msg[i]);
        Integer[] a = { 1, 2, 3 };
        return a;
    }
}

【讨论】:

  • 顺便说一句,关于 AbstractMap 里面的东西,不幸的是,使用 instanceof 无法检测到 GraalVM Polyglot 引擎内部类型,因为它们都不是公共类。在仅支持 GraalVM 的实现中,我猜您应该只使用 Value.asValue() 获得任何输入,然后使用 Value 的 API 从那里获取它,但我很确定 Value 赢了'不喜欢 Nashorn 的代理对象。
猜你喜欢
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 2015-03-01
  • 2014-01-22
  • 2014-10-03
  • 1970-01-01
  • 2014-08-10
相关资源
最近更新 更多