scala Java8 JS Nashorn 将数组转换为 Java 数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22492641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java8 JS Nashorn convert array to Java array
提问by user2053898
How can I convert JS array to native array ? In Rhino conversion looked like (Scala code):
如何将 JS 数组转换为原生数组?在犀牛转换看起来像(Scala 代码):
val eng = (new javax.script.ScriptEngineManager).getEngineByName("JavaScript")
val obj = eng.eval("[1,2,3,4]")
val arr = obj.asInstanceOf[sun.org.mozilla.javascript.internal.NativeArray]
In Nashorn NativeArray absent, and I can't find any documentation on conversion.
在 Nashorn NativeArray 缺席,我找不到任何关于转换的文档。
回答by Attila Szegedi
From Java (and Scala), you can also invoke convertmethod on jdk.nashorn.api.scripting.ScriptUtilsclass. E.g. from Java:
在 Java(和 Scala)中,您还可以convert在jdk.nashorn.api.scripting.ScriptUtils类上调用方法。例如来自 Java:
import jdk.nashorn.api.scripting.ScriptUtils;
...
int[] iarr = (int[])ScriptUtils.convert(arr, int[].class)
my Scala is not too fluent, but I believe the equivalent is:
我的 Scala 不太流利,但我相信相当于:
val iarr = ScriptUtils.convert(arr, Array[Int]).asInstanceOf(Array[Int])
回答by pardeep131085
Given a JavaScript array, you can convert it to a Java array using the Java.to() method in oracle nashorn enginewhich is available in jdk 8
给定一个 JavaScript 数组,您可以使用jdk 8 中提供的oracle nashorn 引擎中的 Java.to() 方法将其转换为 Java 数组
Example
例子
var data = [1,2,3,4,5,6];
var JavaArray = Java.to(data,"int[]");
print(JavaArray[0]+JavaArray[1]+JavaArray[2]);
回答by Nabor
I found a solution that works for Rhino and Nashorn.
我找到了一个适用于 Rhino 和 Nashorn 的解决方案。
First problem, the script writer must not deal with Java Objects!
That leads to a solution, that only uses Java.
第一个问题,脚本编写者不能处理Java对象!
这导致了一个仅使用 Java 的解决方案。
Second it must work with Java 8 and previous versions!
其次,它必须适用于 Java 8 和以前的版本!
final ScriptEngineManager manager = new ScriptEngineManager();
final ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
Object result = convert(engine.eval("(function() {return ['a', 'b'];})()"));
log.debug("Result: {}", result);
result = convert(engine.eval("(function() {return [3, 7.75];})()"));
log.debug("Result: {}", result);
result = convert(engine.eval("(function() {return 'Test';})()"));
log.debug("Result: {}", result);
result = convert(engine.eval("(function() {return 7.75;})()"));
log.debug("Result: {}", result);
result = convert(engine.eval("(function() {return false;})()"));
log.debug("Result: {}", result);
} catch (final ScriptException e) {
e.printStackTrace();
}
private static Object convert(final Object obj) {
log.debug("JAVASCRIPT OBJECT: {}", obj.getClass());
if (obj instanceof Bindings) {
try {
final Class<?> cls = Class.forName("jdk.nashorn.api.scripting.ScriptObjectMirror");
log.debug("Nashorn detected");
if (cls.isAssignableFrom(obj.getClass())) {
final Method isArray = cls.getMethod("isArray");
final Object result = isArray.invoke(obj);
if (result != null && result.equals(true)) {
final Method values = cls.getMethod("values");
final Object vals = values.invoke(obj);
if (vals instanceof Collection<?>) {
final Collection<?> coll = (Collection<?>) vals;
return coll.toArray(new Object[0]);
}
}
}
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {}
}
if (obj instanceof List<?>) {
final List<?> list = (List<?>) obj;
return list.toArray(new Object[0]);
}
return obj;
}
Rhino delivers arrays as class sun.org.mozilla.javascript.internal.NativeArray that implement the java.util.List interface, that are easy to handle
Rhino 将数组作为类 sun.org.mozilla.javascript.internal.NativeArray 提供,实现了 java.util.List 接口,易于处理
13:48:42.400 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class sun.org.mozilla.javascript.internal.NativeArray
13:48:42.405 [main] DEBUG de.test.Tester - Result: [a, b]
13:48:42.407 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class sun.org.mozilla.javascript.internal.NativeArray
13:48:42.407 [main] DEBUG de.test.Tester - Result: [3.0, 7.75]
13:48:42.410 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.String
13:48:42.410 [main] DEBUG de.test.Tester - Result: Test
13:48:42.412 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Double
13:48:42.412 [main] DEBUG de.test.Tester - Result: 7.75
13:48:42.414 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Boolean
13:48:42.415 [main] DEBUG de.test.Tester - Result: false
Nashorn returns a JavaScript array as jdk.nashorn.api.scripting.ScriptObjectMirror that unfortunately doesn't implement the List interface.
I solved it using reflection and I'm wondering why Oracle has made this big change.
Nashorn 返回一个 JavaScript 数组作为 jdk.nashorn.api.scripting.ScriptObjectMirror,不幸的是它没有实现 List 接口。
我使用反射解决了它,我想知道为什么 Oracle 做出了这么大的改变。
13:51:02.488 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class jdk.nashorn.api.scripting.ScriptObjectMirror
13:51:02.495 [main] DEBUG de.test.Tester - Nashorn detected
13:51:02.497 [main] DEBUG de.test.Tester - Result: [a, b]
13:51:02.503 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class jdk.nashorn.api.scripting.ScriptObjectMirror
13:51:02.503 [main] DEBUG de.test.Tester - Nashorn detected
13:51:02.503 [main] DEBUG de.test.Tester - Result: [3.0, 7.75]
13:51:02.509 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.String
13:51:02.509 [main] DEBUG de.test.Tester - Result: Test
13:51:02.513 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Double
13:51:02.513 [main] DEBUG de.test.Tester - Result: 7.75
13:51:02.520 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Boolean
13:51:02.520 [main] DEBUG de.test.Tester - Result: false
回答by user2053898
The solution is Java.to function to do conversion:
解决办法是Java.to函数做转换:
engine.eval("Java.to(" + script + ",'byte[]')").asInstanceOf[Array[Byte]]
engine.eval("Java.to(" + name + ",'java.lang.String[]')").asInstanceOf[Array[String]]
回答by Marko Kraljevic
In case there is array of arrays, we have to process recursivelly:
如果有数组数组,我们必须递归处理:
public class Nashorn {
public static List<String> fromScript(final Object obj){
List<String> returnList = new ArrayList<>();
if(obj==null){
returnList.add("");
return returnList;
}
if (obj instanceof Bindings) {
flatArray(returnList, obj);
return returnList;
}
if (obj instanceof List<?>) {
final List<?> list = (List<?>) obj;
returnList.addAll(list.stream().map(String::valueOf).collect(Collectors.toList()));
return returnList;
}
if(obj.getClass().isArray()){
Object[] array = (Object[])obj;
for (Object anArray : array) {
returnList.add(String.valueOf(anArray));
}
return returnList;
}
returnList.add(String.valueOf(obj));
return returnList;
}
//if we have multiple levels of array, flat the structure
private static void flatArray(List<String> returnList, Object partialArray){
try {
final Class<?> cls = Class.forName("jdk.nashorn.api.scripting.ScriptObjectMirror");
if (cls.isAssignableFrom(partialArray.getClass())) {
final Method isArray = cls.getMethod("isArray");
final Object result = isArray.invoke(partialArray);
if (result != null && result.equals(true)) {
final Method values = cls.getMethod("values");
final Object vals = values.invoke(partialArray);
if (vals instanceof Collection<?>) {
final Collection<?> coll = (Collection<?>) vals;
for(Object el : coll) {
if (cls.isAssignableFrom(el.getClass())) {
flatArray(returnList, el);
}
else{
returnList.add(String.valueOf(el));
}
}
}
}
}
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException ignored) {}
}
}
}
回答by Ercksen
For multidimensional arrays:
对于多维数组:
You can use this code below to get an array with a dynamic dimension, depending on the object you want to convert. There is a usage example below.
您可以使用下面的此代码来获取具有动态维度的数组,具体取决于您要转换的对象。下面有一个使用示例。
public static Object[] toArray(ScriptObjectMirror scriptObjectMirror)
{
if (!scriptObjectMirror.isArray())
{
throw new IllegalArgumentException("ScriptObjectMirror is no array");
}
if (scriptObjectMirror.isEmpty())
{
return new Object[0];
}
Object[] array = new Object[scriptObjectMirror.size()];
int i = 0;
for (Map.Entry<String, Object> entry : scriptObjectMirror.entrySet())
{
Object result = entry.getValue();
System.err.println(result.getClass());
if (result instanceof ScriptObjectMirror && scriptObjectMirror.isArray())
{
array[i] = toArray((ScriptObjectMirror) result);
}
else
{
array[i] = result;
}
i++;
}
return array;
}
Now, use the method like this:
现在,使用这样的方法:
ScriptObjectMirror som = (ScriptObjectMirror) YOUR_NASHORN_ENGINE.eval("['this', ['tricky', ['method', ['works']], 'perfectly'], ':)']");
// create multi-dimensional array
Object[] obj = toArray(som);
And voila, you got it. Below is an example on how to iterate over such arrays:
瞧,你明白了。下面是一个关于如何迭代此类数组的示例:
public static void print(Object o)
{
if (o instanceof Object[])
{
for (Object ob : (Object[]) o)
{
print(ob);
}
}
else
{
System.out.println(o);
}
}
回答by Takami Torao
I success to retrieve java/scala array by using method like traditional netscape.javascript.JSObjectin Java8/Scala2.12/Nashorn.
我成功地使用netscape.javascript.JSObjectJava8/Scala2.12/Nashorn 中的传统方法检索 java/scala 数组。
val arr = engine.eval(script) match {
case obj:ScriptObjectMirror =>
if(obj.isArray){
for(i <- 0 until obj.size()) yield obj.getSlot(i)
} else Seq.empty
case unexpected => Seq.empty
}
Using ScriptUtil()may retrieve scalar value such as String, but it seems to cause ClassCastExceptionfor Array.
UsingScriptUtil()可能会检索诸如 的标量值String,但它似乎会导致ClassCastExceptionArray.

