我找到了一种适用于Rhino和Nashorn的解决方案。
首先,脚本编写者不能处理Java对象!这导致只能使用Java的解决方案。
其次,它必须适用于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将数组作为实现java.util.List接口的sun.org.mozilla.javascript.internal.NativeArray类传递,易于处理。
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返回的JavaScript数组是jdk.nashorn.api.scripting.ScriptObjectMirror,不幸的是它没有实现列表接口。
我使用反射解决了这个问题,不知道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
java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
代码:val eng = (new javax.script.ScriptEngineManager).getEngineByName("JavaScript")
val arr = eng.eval("[1,2,3,4]")println(jdk.nashorn.api.scripting.ScriptUtils.convert(arr, classOf[Array[Byte]]))` - user2053898
int[] iarr = (int[])ScriptUtils.convert(engine.eval("[1,2]"), int[].class);
抛出了java.lang.ClassCastException: Cannot cast jdk.nashorn.api.scripting.ScriptObjectMirror to [I
的异常。我是否漏掉了什么?完整的Java示例(最好不使用Java.to
)会很好。 - salomvary