2011-09-22 5 views
13

Sto iniziando a utilizzare la funzione dinamica rhinoscript in Java 6 per l'utilizzo da parte dei clienti che hanno maggiori probabilità di conoscere Javascript rispetto a Java.Come convertire la mappa Java in un oggetto Javascript di base?

Qual è il modo migliore per passare una mappa (array associativo, javascript obj, qualunque) in Javascript in modo che gli autori di script possano utilizzare la notazione dot standard di Javascript per l'accesso ai valori?

Attualmente sto passando un java.util.Map di valori nello script, tuttavia lo script writer deve scrivere "map.get ('mykey')" invece di "map.mykey".

Fondamentalmente, voglio fare l'opposto di this question.

risposta

2

Hai solo bisogno di codificare l'oggetto come JSON, sia manualmente, oppure utilizzando una libreria come Jackson o gson. Come lei ha detto, è l'oposite esatto di quella domanda e l'autore di tale questione non è felice con la notazione JSON :)

Cosa è necessario inviare al browser è fondamentalmente qualcosa di simile:

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

E quindi lo sviluppatore javascript può semplicemente accedere a: someObject.key2.

+0

Grazie per la vostra risposta rapida! Funziona bene quando si invia JSON a un browser, ma non funziona così bene sul server. Ecco il mio esempio: '\t \t ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName ("javascript"); engine.put ("obj", "{\" key1 \ ": \" valore1 \ ", \" chiave2 \ ": \" valore2 \ "}"); // Restituisce "stringa" anziché "obj". Non voglio rendere // lo script writer eval la stringa, anche se potrebbe essere necessario. engine.eval ("typeof (obj);"); ' –

+0

Dovresti dare un'occhiata a questo http://www.json.org/js.html – Sap

12

ho preso l'approccio Java NativeObject e qui è quello che ho fatto ...

// 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

Questo non sembra funzionare. Scrive "indefinito". Devo ancora accedere alla proprietà con il metodo get: map.get ('ciao'). –

+0

Vedere anche http://stackoverflow.com/questions/37357531/sun-org-mozilla-javascript-internal-nativeobject-vs-org-mozilla-javascript-nativ – Thilo

6

Se si utilizza una classe di utilità che converte Mappa in javascript oggetto hash:

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

Esempio:

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

Dopo aver scoperto che il SimpleScriptContext prenderà solo il Map oggetto e quindi ti costringono ad usare i metodi Java nel tuo JavaScript, ecco cosa ho fatto.

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

Quali stampato

hello world! 
+1

L'ho fatto anche in questo modo, ma usando Jackson. Sono un po 'preoccupato per le prestazioni ora che lo script cambierà sempre. In teoria si potrebbero usare le funzionalità di mappatura degli oggetti di Jackson combinate con il supporto 'NativeObject' (@JonCarlson) per alleviare i problemi di rendimento.L'altra opzione è la scrittura di un javascript generico che segue ricorsivamente le hashmap. –

Problemi correlati