使用Nashorn将ScriptObjectMirror转换为其他Java类

时间:2018-08-28 12:13:08

标签: javascript java nashorn

我想将ScriptObjectMirror对象转换为我自己定义的名为Point的其他类,如下所示:

public class Point {

    public double x;
    public double y;

    public Point(double x, double y) {
        this.x=x;
        this.y=y;
    }

}

我的javascript代码是这样的:

function getCenter(points) {
    var center = {x: 0, y: 0};
    print(points);   
    print(points.length);
    for (var i =0; i < points.length; ++i ) {
        center.x += points[i].x;
        center.y += points[i].y;
    }
    center.x /= points.length;
    center.y /= points.length;
    return center;
}

并且我想通过使用代码提供多个Point来调用js中的getCenter函数:

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    //      engine.eval("print('Hello World!');");
    engine.eval(new FileReader("circleintersection.js"));

    Invocable invocable = (Invocable) engine;

    Point a = new Point(3,2);
    Point b = new Point(5,3);
    Point c = new Point(1,4);
    Point d = new Point(2,5);
    Point e = new Point(6,6);

    Point[] points = {a,b,c,d,e};

    Point result = (Point) invocable.invokeFunction("getCenter", points);
    System.out.println(result.x);

但这给了我类似

的错误
  

线程“ main”中的异常java.lang.ClassCastException:   jdk.nashorn.api.scripting.ScriptObjectMirror无法转换为Point

我尝试了另一种使用代码转换为Map的方法:

@SuppressWarnings("restriction")
    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;
        }
    }

在main()方法中,代码是这样的:

ScriptObjectMirror result = (ScriptObjectMirror) invocable.invokeFunction("getCenter", points);
    Object con = convertIntoJavaObject(result);
    Map<String, Object> map = (Map<String, Object>) con;
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }

,但打印出x:NaN和y:NaN作为结果。

我将变量插入javascript代码或获取结果的方式有问题吗?

1 个答案:

答案 0 :(得分:0)

当您尝试将以下打印语句添加到脚本中时,(还将toString添加到Point类中)

print(points);   
print(points.length);

您可以看到它打印出来,

Point(x=3.0, y=2.0) //the first point
undefined

因此,很明显,只有数组中的第一个值才传递给javascript函数。由于points.length是未定义的,因此您会在JavaScript代码本身中得到一个NaN。

我找不到原因(如果可以找到有效的解释,我会更新答案)

但是,如果您愿意将JavaScript代码更改为使用arguments

,则可以解决此问题
function getCenter() {
    var center = {x: 0, y: 0};
    for (var i =0; i < arguments.length; ++i ) {
        center.x += arguments[i].x;
        center.y += arguments[i].y;
    }
    center.x /= arguments.length;
    center.y /= arguments.length;
    return center;
}

请参阅:Is it possible to send a variable number of arguments to a JavaScript function?