2011-09-22 124 views
13

我開始在Java 6中使用動態rhinoscript功能,供更可能比Java知道Javascript的客戶使用。如何將Java Map轉換爲基本的Javascript對象?

將JavaScript(關聯數組,javascript obj,whatever)傳遞到Javascript中的最佳方式是什麼,以便腳本編寫者可以使用標準的Javascript點表示法來訪問值?

我正在向腳本傳遞值的java.util.Map,然而腳本編寫者必須編寫「map.get('mykey')」而不是「map.mykey」。

基本上,我想要做的this question.

回答

2

你只需要你的對象編碼爲JSON相反,手動,或使用圖書館像Jacksongson。至於你說的,那就是問題,這個問題的作者的確切oposite是不愉快的JSON符號:)

你需要發送給瀏覽器的基本上是這樣的:

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

然後JavaScript開發人員可以簡單訪問:someObject.key2

+0

感謝您的快速反應!將JSON發送到瀏覽器時效果很好,但在服務器上效果不佳。這裏是我的例子: '\t \t ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName(「javascript」); (「obj」,「{\」key1 \「:\」value1 \「,\」key2 \「:\」value2 \「}」); //這將返回「string」而不是「obj」。我不想讓 //腳本編寫器評估字符串,雖然我可能不得不。 engine.eval(「typeof(obj);」); ' –

+0

你應該看看這個http://www.json.org/js.html – Sap

12

我把Java的NativeObject辦法,這裏是我做過什麼......

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

這似乎並不奏效。它寫道「未定義」。我仍然需要通過get方法訪問屬性:map.get('bye')。 –

+0

另請參閱http://stackoverflow.com/questions/37357531/sun-org-mozilla-javascript-internal-nativeobject-vs-org-mozilla-javascript-nativ – Thilo

6

我使用的地圖轉換成JavaScript哈希對象的實用工具類:

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

樣品:

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

確定後SimpleScriptContext只會採取Map對象並因此強制您在JavaScript中使用Java方法,這是我所做的。

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

哪個打印出來

hello world! 
+1

我也這樣做了,但使用傑克遜。現在我對錶演略有擔心,因爲劇本將一直在改變。從理論上講,可以將Jackson的對象映射功能與「NativeObject」(@JonCarlson)支持相結合來緩解性能問題。另一種選擇是寫一個通用的JavaScript遞歸散步hashmaps。 –

相關問題