如何在不使用“internal”子包的类的情况下在Nashorn中包装到NativeArray

时间:2018-01-12 12:40:43

标签: java nashorn

我有一个Java数组,比如说,Object[],我需要传递给JS执行环境ScriptEngine

我不能简单地以下列方式将其作为财产:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Object[] array = {1, 2, 3};
engine.put("prop", array);

因为在JS环境中,表达式Array.isArray(prop)将被评估为false,而我需要它true

jdk.nashorn.internal.objects.NativeArray构造函数已关闭,这意味着您无法显式实例化NativeArray

但是,可以使用jdk.nashorn.internal.objects.Global.instance().wrapAsObject将Java数组Object[]转换为NativeArray,并将结果对象识别为JS数组,即Array.isArray将返回对于这个对象是真的。

虽然这给出了期望的结果,但使用internal包中的类并不是一个好主意,如果你使用的是Java 9,那就更糟了。

因此,我想知道,有没有更好的方法为JS执行环境提供Java对象,假设我无法更改JS源,以便该对象被识别为真正的JS数组,即Array.isArray返回true?

2 个答案:

答案 0 :(得分:1)

您可以通过javascript创建本机数组,然后将相应的ScriptObjectMirror转换为List<Object>,看起来该列表将使用本机数组作为底层存储:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");     
ScriptObjectMirror jsArray = (ScriptObjectMirror) engine.eval("var arr = []; arr");

@SuppressWarnings("unchecked")
List<Object> ls = jsArray.to(List.class);
ls.add(1);
ls.add(2);
ls.add(3);

System.out.println(ls); // [1, 2, 3]
engine.eval("print(arr)"); // 1,2,3
engine.eval("print(Array.isArray(arr))"); // true

然后,您可以在Java端使用此列表。

答案 1 :(得分:1)

Nashorn有一个非标准的顶级Java对象,其中包括名为tofrom的有用转换方法。如果你有一个Java数组arr,那么Java.from(arr)将创建一个JS数组作为Java数组的浅表副本。它也适用于任何java.util.Collection

请注意,在大多数情况下,您可以在Nashorn中本地使用Java数组和列表;如果由于某种原因你需要一个真正的JavaScript原生数组(例如使用数组推导函数),你会想要使用这个方法。