2011-09-22 42 views
13

Estoy empezando a utilizar la función dinámica rhinoscript en Java 6 para que la usen los clientes que tienen más probabilidades de conocer Javascript que Java.¿Cómo convertir Java Map a un objeto Javascript básico?

¿Cuál es la mejor manera de pasar un mapa (matriz asociativa, obj de JavaScript, lo que sea) a Javascript para que los guionistas puedan usar la notación de puntos de JavaScript estándar para acceder a los valores?

Actualmente estoy pasando un java.util.Map de valores en el script, sin embargo, el guionista debe escribir "map.get ('mykey')" en lugar de "map.mykey".

Básicamente, quiero hacer lo contrario de this question.

Respuesta

2

Sólo tiene que codificar el objeto como JSON, ya sea manualmente o utilizando una biblioteca como Jackson o gson. Como usted ha dicho, es el opuesto exacto de la pregunta y el autor de la pregunta no está contento con la notación JSON :)

Lo que hay que enviar al navegador es básicamente algo como esto:

var someObject = { "key1": "value1", "key2": "value2", ... } 

Y luego el desarrollador de javascript puede simplemente acceder: someObject.key2.

+0

Gracias por su respuesta rápida! Eso funciona muy bien cuando se envía JSON a un navegador, pero no funciona tan bien en el servidor. Aquí está mi ejemplo: '\t \t ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName ("javascript"); engine.put ("obj", "{\" clave1 \ ": \" valor1 \ ", \" clave2 \ ": \" valor2 \ "}"); // Esto devuelve "cadena" en lugar de "obj". No quiero hacer // el guionista evalúa la cadena, aunque es posible que deba hacerlo. engine.eval ("typeof (obj);"); ' –

+0

Deberías echarle un vistazo a este http://www.json.org/js.html – Sap

12

Tomé el enfoque de Java NativeObject y aquí es lo que hice ...

// build a Map 
Map<String, String> map = new HashMap<String, String>(); 
map.put("bye", "now"); 

// Convert it to a NativeObject (yes, this could have been done directly) 
NativeObject nobj = new NativeObject(); 
for (Map.Entry<String, String> entry : map.entrySet()) { 
    nobj.defineProperty(entry.getKey(), entry.getValue(), NativeObject.READONLY); 
} 

// Get Engine and place native object into the context 
ScriptEngineManager factory = new ScriptEngineManager(); 
ScriptEngine engine = factory.getEngineByName("javascript"); 
engine.put("map", nobj); 

// Standard Javascript dot notation prints 'now' (as it should!) 
engine.eval("println(map.bye);"); 
+0

Esto no parece funcionar. Escribe "indefinido". Todavía necesito acceder a la propiedad con el método get: map.get ('bye'). –

+0

Ver también http://stackoverflow.com/questions/37357531/sun-org-mozilla-javascript-internal-nativeobject-vs-org-mozilla-javascript-nativ – Thilo

6

Uso una clase de utilidad que se convierten en mapa javascript hash de objeto:

import java.util.Collection; 
import java.util.Map; 
import java.util.Set; 
import org.mozilla.javascript.Scriptable; 
public class MapScriptable implements Scriptable, Map { 
    public final Map map; 
    public MapScriptable(Map map) { 
     this.map = map; 
    } 
    public void clear() { 
     map.clear(); 
    } 
    public boolean containsKey(Object key) { 
     return map.containsKey(key); 
    } 
    public boolean containsValue(Object value) { 
     return map.containsValue(value); 
    } 
    public Set entrySet() { 
     return map.entrySet(); 
    } 
    public boolean equals(Object o) { 
     return map.equals(o); 
    } 
    public Object get(Object key) { 
     return map.get(key); 
    } 
    public int hashCode() { 
     return map.hashCode(); 
    } 
    public boolean isEmpty() { 
     return map.isEmpty(); 
    } 
    public Set keySet() { 
     return map.keySet(); 
    } 
    public Object put(Object key, Object value) { 
     return map.put(key, value); 
    } 
    public void putAll(Map m) { 
     map.putAll(m); 
    } 
    public Object remove(Object key) { 
     return map.remove(key); 
    } 
    public int size() { 
     return map.size(); 
    } 
    public Collection values() { 
     return map.values(); 
    } 
    @Override 
    public void delete(String name) { 
     map.remove(name); 
    } 
    @Override 
    public void delete(int index) { 
     map.remove(index); 
    } 
    @Override 
    public Object get(String name, Scriptable start) { 
     return map.get(name); 
    } 
    @Override 
    public Object get(int index, Scriptable start) { 
     return map.get(index); 
    } 
    @Override 
    public String getClassName() { 
     return map.getClass().getName(); 
    } 
    @Override 
    public Object getDefaultValue(Class<?> hint) { 
     return toString(); 
    } 
    @Override 
    public Object[] getIds() { 
     Object[] res=new Object[map.size()]; 
     int i=0; 
     for (Object k:map.keySet()) { 
      res[i]=k; 
      i++; 
     } 
     return res; 
    } 
    @Override 
    public Scriptable getParentScope() { 
     return null; 
    } 
    @Override 
    public Scriptable getPrototype() { 
     return null; 
    } 
    @Override 
    public boolean has(String name, Scriptable start) { 
     return map.containsKey(name); 
    } 
    @Override 
    public boolean has(int index, Scriptable start) { 
     return map.containsKey(index); 
    } 
    @Override 
    public boolean hasInstance(Scriptable instance) { 
     return false; 
    } 
    @Override 
    public void put(String name, Scriptable start, Object value) { 
     map.put(name, value); 
    } 
    @Override 
    public void put(int index, Scriptable start, Object value) { 
     map.put(index, value); 
    } 
    @Override 
    public void setParentScope(Scriptable parent) {} 
    @Override 
    public void setPrototype(Scriptable prototype) {} 
} 

muestra:

import java.util.HashMap; 
import java.util.Map; 
import org.mozilla.javascript.Context; 
import org.mozilla.javascript.ScriptableObject; 

public class MapScriptableMain { 
    public static void main(String[] args) { 
     Map src=new HashMap(); 
     src.put("foo", 2); 
     src.put("bar", 3); 
     MapScriptable m=new MapScriptable(src); 
     Context c=Context.enter(); 
     ScriptableObject scope = c.initStandardObjects(); 
     ScriptableObject.putProperty(scope, "m", m); 
     String source = "m.baz=m.foo+m.bar;"; 
     Object a=c.evaluateString(scope, source, "TEST", 1, null); 
     System.out.println(a); // 5.0 
     System.out.println(src.get("baz")); // 5.0; 
    } 
} 
3

Después de descubrir que el SimpleScriptContext solo tomará el Map objeto y por lo tanto le obligan a utilizar los métodos de Java en su JavaScript, esto es lo que hice.

Map<String, String> myMap = new HashMap<String, String>(); 
myMap.put("test", "hello world!"); 

ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); 
Object eval = engine.eval("var map = " + new Gson().toJson(myMap) + ";\n" 
    + "println(map.test);"); 

Qué imprime

hello world! 
+1

Lo hice de esta manera también pero usando Jackson. Estoy un poco preocupado por el rendimiento ahora, ya que el script siempre cambiará. En teoría, se podrían usar las capacidades de mapeo de objetos de Jackson combinadas con el soporte 'NativeObject' (@JonCarlson) para aliviar las preocupaciones sobre el rendimiento.La otra opción es escribir un javascript genérico que camina de forma recursiva por los hashmaps. –

Cuestiones relacionadas