Skip to content Skip to sidebar Skip to footer

Java8 Js Nashorn Convert Array To Java Array

How can I convert JS array to native array ? In Rhino conversion looked like (Scala code): val eng = (new javax.script.ScriptEngineManager).getEngineByName('JavaScript') val obj =

Solution 1:

From Java (and Scala), you can also invoke convert method on jdk.nashorn.api.scripting.ScriptUtils class. E.g. from 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:

val iarr = ScriptUtils.convert(arr, Array[Int]).asInstanceOf(Array[Int])

Solution 2:

Given a JavaScript array, you can convert it to a Java array using the Java.to() method in oracle nashorn engine which is available in jdk 8

Example

vardata = [1,2,3,4,5,6];
var JavaArray = Java.to(data,"int[]");
print(JavaArray[0]+JavaArray[1]+JavaArray[2]);

Solution 3:

I found a solution that works for Rhino and Nashorn.

First problem, the script writer must not deal with Java Objects! That leads to a solution, that only uses Java.

Second it must work with Java 8 and previous versions!

finalScriptEngineManagermanager=newScriptEngineManager();
    finalScriptEngineengine= manager.getEngineByName("JavaScript");
    try {
        Objectresult= 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();
    }

privatestatic 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())) {
                finalMethodisArray= cls.getMethod("isArray");
                finalObjectresult= isArray.invoke(obj);
                if (result != null && result.equals(true)) {
                    finalMethodvalues= cls.getMethod("values");
                    finalObjectvals= values.invoke(obj);
                    if (vals instanceof Collection<?>) {
                        final Collection<?> coll = (Collection<?>) vals;
                        return coll.toArray(newObject[0]);
                    }
                }
            }
        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException
                | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {}
    }
    if (obj instanceof List<?>) {
        final List<?> list = (List<?>) obj;
        return list.toArray(newObject[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

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.String13:48:42.410 [main] DEBUG de.test.Tester - Result: Test
13:48:42.412 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Double13:48:42.412 [main] DEBUG de.test.Tester - Result: 7.7513:48:42.414 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Boolean13: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.

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.String13:51:02.509 [main] DEBUG de.test.Tester - Result: Test
13:51:02.513 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Double13:51:02.513 [main] DEBUG de.test.Tester - Result: 7.7513:51:02.520 [main] DEBUG de.test.Tester - JAVASCRIPT OBJECT: class java.lang.Boolean13:51:02.520 [main] DEBUG de.test.Tester - Result: false

Solution 4:

The solution is Java.to function to do conversion:

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

Solution 5:

In case there is array of arrays, we have to process recursivelly:

publicclassNashorn {

publicstaticList<String> fromScript(final Object obj){
    List<String> returnList = newArrayList<>();

    if(obj==null){
        returnList.add("");
        return returnList;
    }

    if (obj instanceofBindings) {
        flatArray(returnList, obj);
        return returnList;
    }

    if (obj instanceofList<?>) {
        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 structureprivatestaticvoidflatArray(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 instanceofCollection<?>) {
                    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) {}
}

}

Post a Comment for "Java8 Js Nashorn Convert Array To Java Array"