2010-08-13 8 views
10

Veo un comportamiento extraño en la implementación del mapa javax.scripting.Importación de un mapa en javax.scripting entorno de JavaScript

Los ejemplos muestran una línea example de añadir a una lista dentro del entorno JS:

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); 

Sin embargo, si intenta hacer algo similar con un mapa, se ve un comportamiento extraño. Por un lado, si intenta iterar a través de las teclas del mapa, p.

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

No hay manera de obtener las claves mapa - si intenta iterar a través de las teclas, se obtiene método nombres-

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

resultados en:

notifyAll 
removeAll 
containsAll 
contains 
empty 
equals 
... 

En el js context puede direccionar los valores en el mapa con m.get(key) pero no con m[key], y si la clave no existe arroja un error. ¿Alguien puede arrojar algo de luz sobre este comportamiento, o simplemente está roto? Gracias.

+0

Eso es muy interesante. Podría estar iterando sobre los objetos keySet (en Rhino puedes repetir los métodos), pero no estoy seguro. Tendré que probarlo – TheLQ

Respuesta

12

para ... en JavaScript no es lo mismo que para ... cada uno en Java, aunque parezcan similares. for..in en JavaScript itera sobre los nombres de propiedad en un objeto. Los nombres de los métodos están expuestos a Rhino como propiedades en el objeto Java HashMap nativa, al igual que si tuviera el siguiente objeto JavaScript:

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

Mi recomendación es que o bien convertir el conjunto de claves HashMap a una matriz, utilizando el método Set .toArray, u obtiene un iterador usando Set.iterator(). He aquí una breve secuencia de comandos de Rhino que muestran cómo se puede lograr esto usando el método toArray:

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); 
} 

que da salida:

bif 
bar 
boo 

Así es como se puede hacer lo mismo usando 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); 
} 
+0

Gracias, completo y útil. –

2

Si convierte java.util.Map a un objeto nativo, su JavaScript será más limpio:

De lo contrario, está atascado con la sintaxis estándar de Java.

+0

Desafortunadamente, su NativeObject debe estar en la API Rhino o Nashorn. No existe en la API común de javax.script. – jfrantzius

Cuestiones relacionadas