2010-08-13 7 views
10

javax.scripting 맵 구현에서 이상한 동작이 나타납니다.javax.scripting 자바 스크립트 환경에서 맵 가져 오기

온라인 예는 JS 환경 내 목록에 추가하는 example 보여

ScriptEngineManager mgr = new ScriptEngineManager(); 
    ScriptEngine jsEngine = mgr.getEngineByName("JavaScript"); 
    List<String> namesList = new ArrayList<String>(); 
    namesList.add("Jill"); 
    namesList.add("Bob"); 
    namesList.add("Laureen"); 
    namesList.add("Ed"); 
    jsEngine.put("namesListKey", namesList); 
    System.out.println("Executing in script environment..."); 
    try 
    { 
    jsEngine.eval("var names = namesListKey.toArray();" + "for(x in names) {" + " println(names[x]);" + "}" 
    + "namesListKey.add(\"Dana\");"); 
    } catch (ScriptException ex) 
    { 
    ex.printStackTrace(); 
    } 
    System.out.println(namesList); 

을하지만, 당신이지도와 비슷한 뭔가를하려고하면, 당신은 이상한 행동을 참조하십시오. 한 가지 예로지도 키를 반복 할 때 (예 :

HashMap<String, Object> m = new HashMap<String, Object>(); 
jsEngine.put("map", m); 

지도 키를 얻을 수있는 방법은 없습니다 - 당신이 키를 반복하려고하면, 당신은 방법을 얻을 names-에

jsEngine.eval(" for (var k in m.keySet()){ println(k)};"); 

결과 : JS에서

notifyAll 
removeAll 
containsAll 
contains 
empty 
equals 
... 

컨텍스트에서 m.get(key)으로 맵의 값을 지정할 수는 있지만 m[key]으로 설정하면 안됩니다. 키가 존재하지 않으면 오류가 발생합니다. 누구든지이 행동에 대해 밝히지 않습니까, 아니면 그냥 깨졌습니까? 감사.

+0

매우 흥미로운 부분입니다. keySet 객체를 반복 할 수도 있습니다 (Rhino에서는 메서드를 반복 할 수 있습니다). 그러나 확실하지 않습니다. 그것을 시도해야합니다 – TheLQ

답변

12

for..in JavaScript는 for와 유사하지 않습니다. Java에서도 마찬가지입니다. JavaScript의 for..in은 객체의 속성 이름을 반복합니다.

{ 
notifyAll:function(){}, 
removeAll:function(){}, 
containsAll:function(){}, 
contains:function(){}, 
empty:function(){}, 
equals:function(){} 
} 

나의 추천 당신이 방법의 설정을 사용하여 배열에 HashMap의 키 집합 변환 중 하나이다 : 메소드 이름은 다음과 같은 자바 스크립트 객체를 가지고 것처럼, 네이티브 자바의 HashMap 객체에 속성으로 코뿔소에 노출되어있다 .toArray를 사용하거나 Set.iterator()를 사용하여 반복기를 가져옵니다.

x=new java.util.HashMap(); 
x.put("foo","bar"); 
x.put("bat","bif"); 
x.put("barf","boo"); 

var keyArray = x.keySet().toArray(); 
for(var i=0, l = keyArray.length; i < l; i++){ 
    var key = keyArray[i]; 
    var value = x.get(key); 
    print(value); 
} 

출력 : 여기에

bif 
bar 
boo 

당신이 Set.iterator 사용하여 같은 일을 할 수있는 방법은 다음과 같습니다

x=new java.util.HashMap(); 
x.put("foo","bar"); 
x.put("bat","bif"); 
x.put("barf","boo"); 

var keyIter = x.keySet().iterator(); 
while(keyIter.hasNext()){ 
    var key = keyIter.next() 
    var value = x.get(key); 
    print(value); 
} 
여기에 짧은 코뿔소 스크립트는 toArray 방법을 사용하여이 작업을 수행 할 수있는 방법을 보여주는 것
+0

감사합니다, 철저하고 유용합니다. –

2

java.util.Map을 기본 객체로 변환하면 JavaScript가 더 깨끗하게됩니다.

final Map<String,String> javaMap = new HashMap<>(); 
javaMap.put("alpha", "bravo"); 
javaMap.put("charlie", "delta"); 

final NativeObject jsMap = new NativeObject(); 
for (Map.Entry<String,String> entry : javaMap.entrySet()) { 
    jsMap.defineProperty(
     entry.getKey(), entry.getValue(), NativeObject.READONLY 
    ); 
} 

final ScriptEngine jsEngine = 
(new ScriptEngineManager()).getEngineByName("JavaScript"); 
jsEngine.put("map", jsMap); 
jsEngine.eval(
    "for (var idx in map) print(idx + '; ' + map[idx] + '\\n');" 
); 

그렇지 않으면 표준 Java 구문을 사용해야합니다.

+0

아쉽게도 NativeObject는 Rhino 또는 Nashorn API 중 하나 여야합니다. javax.script 공통 API에는 존재하지 않습니다. – jfrantzius

관련 문제