有没有办法使用Object.keys()使Nashorn JSObject的自定义实现工作?

时间:2017-05-28 21:05:05

标签: java-8 nashorn

我最近问了这个问题How can I pass a proper method reference in so Nashorn can execute it?并得到了一个答案,帮助我进一步完成了我的项目,但我发现了一个限制,提供了一个我不知道如何解决的自定义JSObject实现

鉴于这个简单易用的JSObject可以处理JS在其上调用的大多数方法,例如map:

import javax.script.*;
import jdk.nashorn.api.scripting.*;
import java.util.*;
import java.util.function.*;

public class scratch_6 {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager m = new ScriptEngineManager();
        ScriptEngine e = m.getEngineByName("nashorn");

        // The following JSObject wraps this list
        List<Object> l = new ArrayList<>();
        l.add("hello");
        l.add("world");
        l.add(true);
        l.add(1);

        JSObject jsObj = new AbstractJSObject() {
            @Override
            public Object getMember(String name) {
                if (name.equals("map")) {
                    // return a functional interface object - nashorn will treat it like
                    // script function!
                    final Function<JSObject, Object> jsObjectObjectFunction = callback -> {
                        List<Object> res = new ArrayList<>();
                        for (Object obj : l) {
                            // call callback on each object and add the result to new list
                            res.add(callback.call(null, obj));
                        }

                        // return fresh list as result of map (or this could be another wrapper)
                        return res;
                    };
                    return jsObjectObjectFunction;
                } else {
                    // unknown property
                    return null;
                }
            }
        };

        e.put("obj", jsObj);
        // map each String to it's uppercase and print result of map
        e.eval("print(obj.map(function(x) '\"'+x.toString()+'\"'))");

        //PROBLEM
        //e.eval("print(Object.keys(obj))");
    }
}

如果取消注释调用Object.keys(obj)的最后一行,它将失败并显示错误... is not an Object

这似乎是因为Object.keys()[NativeObject.java:376]仅检查对象是ScriptObject还是ScriptObjectMirror的实例。如果它既不是那些东西,它会抛出notAnObject错误。 :(

1 个答案:

答案 0 :(得分:2)

理想情况下,用户实现的JSObject对象应该与脚本对象完全等效。但是,用户实现的JSObjects几乎是 脚本对象 - 但并不完全。这在此处记录 - &gt; https://github.com/SimulatedGREG/electron-vue/

Object.keys就是这样一种情况,它会中断。但是,如果你只想在你的对象的javascript迭代支持中,你可以在你的类中实现JSObject.keySet。

示例代码:

import javax.script.*;
import jdk.nashorn.api.scripting.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager m = new ScriptEngineManager();
        ScriptEngine e = m.getEngineByName("nashorn");

        // This JSObject wraps the following Properties object
        Properties props = System.getProperties();

        JSObject jsObj = new AbstractJSObject() {
            @Override
            public Set<String> keySet() {
                return props.stringPropertyNames();
            }

            @Override
            public Object getMember(String name) {
                return props.getProperty(name);
            }
        };

        e.put("obj", jsObj);
        e.eval("for (i in obj) print(i, ' = ', obj[i])");
    }
}