Java8 JS Nashorn将数组转换为Java数组

use*_*898 14 javascript arrays scala nashorn

如何将JS数组转换为本机数组?在Rhino转换看起来像(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]
Run Code Online (Sandbox Code Playgroud)

在Nashorn NativeArray缺席,我找不到任何关于转换的文档.

Att*_*edi 16

从Java(和Scala),您还可以convertjdk.nashorn.api.scripting.ScriptUtils类上调用方法.例如来自Java:

import jdk.nashorn.api.scripting.ScriptUtils;
...
int[] iarr = (int[])ScriptUtils.convert(arr, int[].class)
Run Code Online (Sandbox Code Playgroud)

我的Scala不太流利,但我相信相当于:

val iarr = ScriptUtils.convert(arr, Array[Int]).asInstanceOf(Array[Int])
Run Code Online (Sandbox Code Playgroud)

  • 我遇到了麻烦.`int [] iarr =(int [])ScriptUtils.convert(engine.eval("[1,2]"),int [] .class);`throws` java.lang.ClassCastException:无法强制转换jdk.nashorn. api.scripting.ScriptObjectMirror到[I`.我错过了什么吗?一个完整的Java示例(最好不使用`Java.to`)会很好. (4认同)

par*_*085 8

给定一个JavaScript数组,您可以使用oracle nashorn引擎中的Java.to()方法将其转换为Java数组,该引擎可在jdk 8中使用

var data = [1,2,3,4,5,6];

var JavaArray = Java.to(data,"int []");

print(JavaArray [0] + JavaArray 1 + JavaArray [2]);


Nab*_*bor 6

我找到了适用于Rhino和Nashorn的解决方案.

第一个问题,脚本编写者不得处理Java Objects!
这导致了一个只使用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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


use*_*898 2

解决办法是用Java.to函数来做转换:

engine.eval("Java.to(" + script + ",'byte[]')").asInstanceOf[Array[Byte]]
engine.eval("Java.to(" + name + ",'java.lang.String[]')").asInstanceOf[Array[String]]
Run Code Online (Sandbox Code Playgroud)