Nashorn ScriptObjectMirror JS - > Java类型转换

时间:2015-11-10 14:33:13

标签: java java-8 nashorn scriptengine

当我使用Nashorn ScriptObjectMirror.get()访问JavaScript对象的成员变量时,返回的对象的类型似乎是在运行时确定的。例如,如果值适合Java int,则get()似乎返回Java Integer。如果该值不适合int,则get()似乎返回Java Long,依此类推。

现在,我使用instanceof检查类型并将值转换为long。

是否有更方便的方法来获取成员的价值而不会丢失并且不检查Java中的类型?也许Nashorn总是可以给我一个Java Double,如果成员不是数字,就会抛出错误。

我可以想象这是一个相当狭窄的案例,可能不应该由Nashorn处理......

示例:

package com.tangotangolima.test.nashorn_types;

import jdk.nashorn.api.scripting.ScriptObjectMirror;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.StringReader;

public class Main {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager mgr = new ScriptEngineManager();
        final ScriptEngine js = mgr.getEngineByName("nashorn");

        final String script = "" +
                "var p = 1;" +
                "var q = " + (Integer.MAX_VALUE + 1L) + ";" +
                "var r = {" +
                "s: 1," +
                "t: " + (Integer.MAX_VALUE + 1L) +
                " };";

        js.eval(new StringReader(script));

        say(js.get("p").getClass().getName());      // -> java.lang.Integer
        say(js.get("q").getClass().getName());      // -> java.lang.Long

        final ScriptObjectMirror r = (ScriptObjectMirror) js.get("r");

        say(r.get("s").getClass().getName());       // -> java.lang.Integer
        say(r.get("t").getClass().getName());       // -> java.lang.Long
    }

    static void say(String s) {
        System.out.println(s);
    }
}

3 个答案:

答案 0 :(得分:8)

此代码可以执行ScriptObjectMirror JS - > Java转换

private static Object convertIntoJavaObject(Object scriptObj) {
    if (scriptObj instanceof ScriptObjectMirror) {
        ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) scriptObj;
        if (scriptObjectMirror.isArray()) {
            List<Object> list = Lists.newArrayList();
            for (Map.Entry<String, Object> entry : scriptObjectMirror.entrySet()) {
                list.add(convertIntoJavaObject(entry.getValue()));
            }
            return list;
        } else {
            Map<String, Object> map = Maps.newHashMap();
            for (Map.Entry<String, Object> entry : scriptObjectMirror.entrySet()) {
                map.put(entry.getKey(), convertIntoJavaObject(entry.getValue()));
            }
            return map;
        }
    } else {
        return scriptObj;
    }
}

public static void main(String[] args) throws ScriptException, NoSuchMethodException {
    final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    engine.eval("function objProvider(){return {a:1, b:'2','c': true,'d': {'e':[],'f':['1',{'g':45}]}};}");
    final Object scriptObj = ((Invocable) engine).invokeFunction("objProvider");

    Object javaObj = convertIntoJavaObject(scriptObj);
    System.out.println(javaObj);
    //{a=1, b=2, c=true, d={e=[], f=[1, {g=45}]}}
}

答案 1 :(得分:2)

推荐的方法是从java代码检查“instanceof java.lang.Number” - 如果你期望JavaScript“number”值。一旦转换为Number,您可以通过调用intValue,longValue等方法将其转换为int,long,double。

答案 2 :(得分:1)

我非常喜欢Igor's方法。这是他的{ "menfou": 10 } 代码,是仅使用标准Java的完整程序,并且除了包含convertToJavaObject()之外,还包含一个toJava(),反之亦然。

toJavascript()