Java Nashorn 引擎 ArrayNode 处理

Java Nashorn engine ArrayNode handling

我使用 Java Nashorn 引擎 来执行 Java 脚本代码。我使用 ScriptEngine objecteval 方法,它具有 "bindings" 的第二个参数。我用它来将变量传递给引擎。它适用于对象类型和原始包装器 类,但是当我尝试传递 ArrayNode 时,它​​不能用作 JavaScript 数组,我不知道为什么。

示例代码:

String scriptText = "myarray[1] = 666";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Bindings bindings = engine.createBindings();
ArrayNode arrayNode = mapper.createArrayNode();
array.add(1);
array.add(2);
array.add(3);

bindings.put("myarray", arrayNode);
engine.eval(scriptText, bindings);

这应该会更改绑定对象中的 myarray 值,但实际上并没有。

我做错了什么?

Nashorn 在

上支持脚本数组索引 access/update
  1. Java 数组对象
  2. java.util.ArrayList 个对象
  3. jdk.nashorn.api.scripting.JSObject 个对象

如果 ArrayNode 不是 ArrayList 子类型,您可以在 ArrayNode class 中实现 JSObject 接口,或者用 JSObject 实现包装 ArrayNode 并将其暴露给脚本 (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/JSObject.html)。

上述三种情况的示例:

import java.util.*;
import javax.script.*;
import jdk.nashorn.api.scripting.*;

public class Main {
  public static void main(String[] args) throws Exception {
    ScriptEngineManager m = new ScriptEngineManager();
    ScriptEngine e = m.getEngineByName("nashorn");

    // Java array accessed by indexing
    String[] arr = { "hello", "world" };
    e.put("jarr", arr);
    e.eval("jarr[1] = jarr[1].toUpperCase()"); // change first element
    System.out.println(arr[1]); // change reflected here

    // Java ArrayList accessed by indexing
    ArrayList<String> alist = new ArrayList<>();
    alist.add("nashorn");
    alist.add("javascript");
    e.put("jlist", alist);
    e.eval("jlist[0] = 'Nashorn'");
    System.out.println(alist.get(1)); // change reflected here

    // Third case - a JSObject array-like object accessed by indexing
    e.put("myObj", new AbstractJSObject() {
        private Map<Integer, Object> values = new HashMap<>();
        @Override
        public void setSlot(int index, Object val) {
            values.put(index, val);
        }

        @Override
        public Object getSlot(int index) {
            return values.get(index);
        }
   });

   e.eval("myObj[0] = 'hello'");
   e.eval("print(myObj[0])");
 }
}