2017-05-28 9 views
0

私は最近、この質問をHow can I pass a proper method reference in so Nashorn can execute it?と尋ねました。私のプロジェクトにもっと役立つ答えを得ましたが、解決方法がわからないカスタムJSObject実装を提供することに限界があることがわかりました。Nashorn JSObjectのカスタム実装をObject.keys()で動作させる方法はありますか?

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)が呼び出され、最後の行のコメントを解除した場合、それがされます:JSは、そのようなマップとしてそれを呼び出します。メソッドのほとんどを処理することができ、この単純な作業のJSObjectを考えると

エラー... 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を。。それが壊れるそのような場合は、

あなたは自分のオブジェクトのためのjavascriptにfor..inイテレーションサポートをしたい場合は、あなたがあなたのクラスで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のRFEをScriptObjectMirrorの代わりにJSObjectのObject.keysテストを行う価値があるのでしょうか? – deinspanjer

+0

はい、openjdkに対してバグ/ rfeを提出してください。 –

+0

RFEファイル、内部レビューID:9049306 – deinspanjer

関連する問題