Java 8 有没有办法让Nashorn JSObject的自定义实现与Object.keys()一起工作?

Java 8 有没有办法让Nashorn JSObject的自定义实现与Object.keys()一起工作?,java-8,nashorn,Java 8,Nashorn,我最近问了这个问题,得到了一个帮助我在项目中走得更远的答案,但我发现了一个局限性,即提供一个我不知道如何解决的自定义JSObject实现 考虑到这个简单的工作JSObject可以处理JS将在其上调用的大多数方法,例如map: import javax.script.*; import jdk.nashorn.api.scripting.*; import java.util.*; import java.util.function.*; public class scratch_6 {

我最近问了这个问题,得到了一个帮助我在项目中走得更远的答案,但我发现了一个局限性,即提供一个我不知道如何解决的自定义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))");
    }
}
import javax.script.*;
导入jdk.nashorn.api.scripting.*;
导入java.util.*;
导入java.util.function.*;
公共课6{
公共静态void main(字符串[]args)引发异常{
ScriptEngineManager m=新ScriptEngineManager();
ScriptEngine e=m.getEngineByName(“nashorn”);
//下面的JSObject包装了这个列表
列表l=新的ArrayList();
l、 加上(“你好”);
l、 添加(“世界”);
l、 添加(真);
l、 增加(1);
JSObject jsObj=新的AbstractJSObject(){
@凌驾
公共对象getMember(字符串名称){
if(name.equals(“map”)){
//返回一个函数接口对象-nashorn会像
//脚本函数!
最终函数JSObjectFunction=回调->{
List res=new ArrayList();
用于(对象对象对象:l){
//对每个对象调用callback并将结果添加到新列表中
res.add(callback.call(null,obj));
}
//作为映射的结果返回新列表(或者这可能是另一个包装器)
返回res;
};
返回jsObjectObjectFunction;
}否则{
//未知属性
返回null;
}
}
};
e、 put(“obj”,jsObj);
//将每个字符串映射到其大写字母,并打印映射结果
e、 eval(“打印(对象映射(函数(x)\”'+x.toString()+'\“'))”;
//问题
//e、 eval(“打印(Object.keys(obj))”;
}
}
如果取消注释调用Object.keys(obj)的最后一行,它将失败,并出现错误
。。。不是对象


这似乎是因为Object.keys()[NativeObject.java:376]只检查对象是ScriptObject还是ScriptObjectMirror的实例。如果两者都不是,则抛出notAnObject错误(

理想情况下,用户实现的JSObject对象应该完全等同于脚本对象。但是,用户实现的JSObject几乎都是脚本对象,但不完全是。这里有文档记录->

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])");
    }
}
import javax.script.*;
导入jdk.nashorn.api.scripting.*;
导入java.util.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
ScriptEngineManager m=新ScriptEngineManager();
ScriptEngine e=m.getEngineByName(“nashorn”);
//此JSObject包装了以下属性对象
Properties props=System.getProperties();
JSObject jsObj=新的AbstractJSObject(){
@凌驾
公共集密钥集(){
返回props.stringPropertyNames();
}
@凌驾
公共对象getMember(字符串名称){
返回props.getProperty(名称);
}
};
e、 put(“obj”,jsObj);
e、 eval(“对于(obj中的i)打印(i,“=”,obj[i])”;
}
}

理想情况下,用户实现的JSObject对象应该完全等同于脚本对象。但是,用户实现的JSObject几乎都是脚本对象,但不完全是。这在这里有文档记录->

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])");
    }
}
import javax.script.*;
导入jdk.nashorn.api.scripting.*;
导入java.util.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
ScriptEngineManager m=新ScriptEngineManager();
ScriptEngine e=m.getEngineByName(“nashorn”);
//此JSObject包装了以下属性对象
Properties props=System.getProperties();
JSObject jsObj=新的AbstractJSObject(){
@凌驾
公共集密钥集(){
返回props.stringPropertyNames();
}
@凌驾
公共对象getMember(字符串名称){
返回props.getProperty(名称);
}
};
e、 put(“obj”,jsObj);
e、 eval(“对于(obj中的i)打印(i,“=”,obj[i])”;
}
}

我在JDK JIRA中找到了,上面写着Object.keys()不适用于Java对象,但请注意,本例中的区别在于,我的类正在实现JSObject,这对我来说意味着它应该是兼容的。我还发现它涉及到类似的领域,并实现了一个修复程序,但该修复程序没有涵盖JSObject接口本身。我在JDK JIRA中找到了该对象。keys()不适用于Java对象,但请注意,本例中的区别在于,我的类正在实现JSObject,这对我来说意味着它应该是兼容的。我还发现它涉及一个类似的领域,并实现了一个修复程序,但修复程序没有涵盖JSObject接口本身。不幸的是,我调用了第三方代码使用Object.keys(),这样我就没有选择将其替换为其他内容。是否值得为jdk9添加一个RFE,以便对JSObject进行Object.keys测试,而不仅仅是ScriptObjectMirror?是的,请针对openjdk.RFE文件提交一个bug/RFE,内部审核ID:90493