如何将 Java Map 转换为基本的 Javascript 对象?

Posted

技术标签:

【中文标题】如何将 Java Map 转换为基本的 Javascript 对象?【英文标题】:How to convert Java Map to a basic Javascript object? 【发布时间】:2011-11-23 01:55:43 【问题描述】:

我开始使用 Java 6 中的动态 rhinoscript 功能,供更可能了解 javascript 而非 Java 的客户使用。

将 Map(关联数组、javascript obj 等)传递到 Javascript 以便脚本编写者可以使用标准 Javascript 点符号来访问值的最佳方法是什么?

我目前正在将值的 java.util.Map 传递到脚本中,但是脚本编写者必须编写“map.get('mykey')”而不是“map.mykey”。

基本上,我想做与this question.相反的事情

【问题讨论】:

【参考方案1】:

我采用了 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);");

【讨论】:

这似乎不起作用。它写“未定义”。我仍然需要使用 get 方法访问该属性:map.get('bye')。 另见***.com/questions/37357531/…【参考方案2】:

我正在使用将 Map 转换为 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!

【讨论】:

我也是这样做的,但使用的是杰克逊。我现在有点担心性能,因为脚本总是在变化。理论上,可以使用 Jackson 的对象映射功能与 NativeObject (@JonCarlson) 支持相结合来缓解性能问题。另一种选择是编写一个递归遍历 hashmap 的通用 javascript。【参考方案4】:

您只需将对象编码为JSON,可以手动编码,也可以使用Jackson 或gson 等库。正如您所说,这与该问题完全相反,并且该问题的作者对 JSON 表示法不满意 :)

您需要发送到浏览器的内容基本上是这样的:

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

然后 javascript 开发人员可以简单地访问:someObject.key2

【讨论】:

感谢您的快速回复!将 JSON 发送到浏览器时效果很好,但在服务器上效果不佳。这是我的示例:` ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine 引擎 = factory.getEngineByName("javascript"); engine.put("obj", " \"key1\": \"value1\", \"key2\": \"value2\""); // 这将返回“字符串”而不是“obj”。我不想让脚本编写者评估字符串,尽管我可能不得不这样做。 engine.eval("typeof(obj);"); '

以上是关于如何将 Java Map 转换为基本的 Javascript 对象?的主要内容,如果未能解决你的问题,请参考以下文章

java如何将json的数据转换为map或者list类型的?

如何将 XML 转换为 java.util.Map,反之亦然?

如何通过 scala.Float 到 java.Float k/v 转换将 Scala Map 转换为 Java Map

java中如何map转换为数组

Java中如何把字符串转换成map

java在后台如何将前台传过来的json格式数据转换为map?