2017-05-28 126 views
0

我最近问这个问题How can I pass a proper method reference in so Nashorn can execute it?,得到了一个答案,帮助我进一步了解我的项目,但是我发现了一个限制,提供了一个我不知道如何解决的自定义JSObject实现。有没有办法使用Object.keys()来实现Nashorn JSObject的自定义实现?

鉴于这种简单的工作JSObject,能够处理大多数的方法JS将它援引如地图:

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错误。 :(

+0

我在JDK JIRA中发现了https://bugs.openjdk.java.net/browse/JDK-8154720,它表示Object.keys()不适用于Java对象,但请注意在这种情况下的区别是我的班级正在实施JSObject,这意味着它应该是兼容的。 – deinspanjer

+0

我还发现https://bugs.openjdk.java.net/browse/JDK-8015830触及类似的区域,并实施了一个修复程序,但修复程序不包括JSObject接口本身。 – deinspanjer

回答

2

理想的情况下,用户实现的JSObject对象应该完全等同于脚本对象,但用户实现JSObjects是几乎脚本对象 - 但不太这是记录在这里 - >https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes

Object.keys就是这样的一个情况下它打破但是,如果你只是想的for..in迭代的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])"); 
    } 
} 
+0

不幸的是,我打电话到正在使用Object.keys()的第三方代码中,所以我没有选择将它交换出来。对于jdk9来说,为了让Object.keys测试JSObject而不是仅仅使用ScriptObjectMirror,是否值得将RFE放入? – deinspanjer

+0

是的,请对openjdk提出bug/rfe。 –

+0

RFE提交,内部审查ID:9049306 – deinspanjer

相关问题