如何使用Gson将JSON转换为HashMap?

我正在从一个返回JSON格式的数据的服务器请求数据。 提出请求时,将HashMap转换为JSON并不难,但另一方面似乎有点棘手。 JSON响应如下所示:

{ "header" : { "alerts" : [ { "AlertID" : "2", "TSExpires" : null, "Target" : "1", "Text" : "woot", "Type" : "1" }, { "AlertID" : "3", "TSExpires" : null, "Target" : "1", "Text" : "woot", "Type" : "1" } ], "session" : "0bc8d0835f93ac3ebbf11560b2c5be9a" }, "result" : "4be26bc400d3c" } 

访问这些数据最简单的方法是什么? 我正在使用GSON模块。

干得好

 Type type = new TypeToken<Map<String, String>>(){}.getType(); Map<String, String> myMap = gson.fromJson("{'k1':'apple','k2':'orange'}", type); 

此代码工作:

 Gson gson = new Gson(); String json = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; Map<String,Object> map = new HashMap<String,Object>(); map = (Map<String,Object>) gson.fromJson(json, map.getClass()); 

我知道这是一个相当古老的问题,但我正在寻找一种解决方案,将嵌套的JSON一般反序列化为一个Map<String, Object> ,并且什么都没找到。

我的yaml反序列化器的工作方式是,当你不指定类型时,默认JSON对象为Map<String, Object> ,但是gson似乎没有这样做。 幸运的是,你可以用一个自定义的解串器完成它。

我使用了下面的反序列化器来自然地反序列化任何东西,默认的JsonObjectMap<String, Object>JsonArray s设置为Object[] ,其中所有的子类都被类似的反序列化。

 private static class NaturalDeserializer implements JsonDeserializer<Object> { public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { if(json.isJsonNull()) return null; else if(json.isJsonPrimitive()) return handlePrimitive(json.getAsJsonPrimitive()); else if(json.isJsonArray()) return handleArray(json.getAsJsonArray(), context); else return handleObject(json.getAsJsonObject(), context); } private Object handlePrimitive(JsonPrimitive json) { if(json.isBoolean()) return json.getAsBoolean(); else if(json.isString()) return json.getAsString(); else { BigDecimal bigDec = json.getAsBigDecimal(); // Find out if it is an int type try { bigDec.toBigIntegerExact(); try { return bigDec.intValueExact(); } catch(ArithmeticException e) {} return bigDec.longValue(); } catch(ArithmeticException e) {} // Just return it as a double return bigDec.doubleValue(); } } private Object handleArray(JsonArray json, JsonDeserializationContext context) { Object[] array = new Object[json.size()]; for(int i = 0; i < array.length; i++) array[i] = context.deserialize(json.get(i), Object.class); return array; } private Object handleObject(JsonObject json, JsonDeserializationContext context) { Map<String, Object> map = new HashMap<String, Object>(); for(Map.Entry<String, JsonElement> entry : json.entrySet()) map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class)); return map; } } 

handlePrimitive方法内部的混乱是为了确保你只能得到一个Double或者Integer或者Long,如果你还没有得到BigDecimals,我相信这是默认的。

你可以像这样注册这个适配器:

 GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer()); Gson gson = gsonBuilder.create(); 

然后像这样调用它:

 Object natural = gson.fromJson(source, Object.class); 

我不知道为什么这不是gson的默认行为,因为它是在大多数其他半结构化序列化库…

更新新的Gson lib:
您现在可以直接解析嵌套的Json到Map,但是您应该知道如果您尝试将Json解析为Map<String, Object>类型:它将引发异常。 要解决这个问题,只需将结果声明为LinkedTreeMap类型。 示例如下:

 String nestedJSON = "{"id":"1","message":"web_didload","content":{"success":1}}; Gson gson = new Gson(); LinkedTreeMap result = gson.fromJson(nestedJSON , LinkedTreeMap.class); 

用谷歌的Gson 2.7(也许更早的版本,但我用当前版本2.7测试),它是如此简单:

 Map map = gson.fromJson(jsonString, Map.class); 

它返回一个com.google.gson.internal.LinkedTreeMap类型的Map ,并递归地嵌套对象,数组等。

我像这样运行OP示例(简单地用双引号替换双引号并删除空格):

 String jsonString = "{'header': {'alerts': [{'AlertID': '2', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}, {'AlertID': '3', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}], 'session': '0bc8d0835f93ac3ebbf11560b2c5be9a'}, 'result': '4be26bc400d3c'}"; Map map = gson.fromJson(jsonString, Map.class); System.out.println(map.getClass().toString()); System.out.println(map); 

并得到以下输出:

 class com.google.gson.internal.LinkedTreeMap {header={alerts=[{AlertID=2, TSExpires=null, Target=1, Text=woot, Type=1}, {AlertID=3, TSExpires=null, Target=1, Text=woot, Type=1}], session=0bc8d0835f93ac3ebbf11560b2c5be9a}, result=4be26bc400d3c} 

我有完全相同的问题,最终在这里。 我有一个不同的方法,似乎更简单(也许更新版本的GSON?)。

  Gson gson = new Gson(); Map jsonObject = (Map) gson.fromJson(data, Object.class); 

与以下json

 { "map-00": { "array-00": [ "entry-00", "entry-01" ], "value": "entry-02" } } 

下列

  Map map00 = (Map) jsonObject.get("map-00"); List array00 = (List) map00.get("array-00"); String value = (String) map00.get("value"); for (int i = 0; i < array00.size(); i++) { System.out.println("map-00.array-00[" + i + "]= " + array00.get(i)); } System.out.println("map-00.value = " + value); 

输出

 map-00.array-00[0]= entry-00 map-00.array-00[1]= entry-01 map-00.value = entry-02 

在浏览jsonObject时,你可以动态地检查使用instanceof。 就像是

 Map json = gson.fromJson(data, Object.class); if(json.get("field") instanceof Map) { Map field = (Map)json.get("field"); } else if (json.get("field") instanceof List) { List field = (List)json.get("field"); } ... 

它适用于我,所以它必须为你工作;-)

试试这个,它会起作用。 我用它作为Hashtable

 public static Hashtable<Integer, KioskStatusResource> parseModifued(String json) { JsonObject object = (JsonObject) new com.google.gson.JsonParser().parse(json); Set<Map.Entry<String, JsonElement>> set = object.entrySet(); Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator(); Hashtable<Integer, KioskStatusResource> map = new Hashtable<Integer, KioskStatusResource>(); while (iterator.hasNext()) { Map.Entry<String, JsonElement> entry = iterator.next(); Integer key = Integer.parseInt(entry.getKey()); KioskStatusResource value = new Gson().fromJson(entry.getValue(), KioskStatusResource.class); if (value != null) { map.put(key, value); } } return map; } 

KioskStatusResource替换为您的类,将Integer替换为您的键类。

这是我一直在使用的:

 public static HashMap<String, Object> parse(String json) { JsonObject object = (JsonObject) parser.parse(json); Set<Map.Entry<String, JsonElement>> set = object.entrySet(); Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator(); HashMap<String, Object> map = new HashMap<String, Object>(); while (iterator.hasNext()) { Map.Entry<String, JsonElement> entry = iterator.next(); String key = entry.getKey(); JsonElement value = entry.getValue(); if (!value.isJsonPrimitive()) { map.put(key, parse(value.toString())); } else { map.put(key, value.getAsString()); } } return map; } 

我已经克服了与自定义JsonDeSerializer类似的问题。 我试图使它有点通用,但仍然不够。 这是一个解决方案,但这符合我的需求。

首先你需要为Map对象实现一个新的JsonDeserializer。

 public class MapDeserializer<T, U> implements JsonDeserializer<Map<T, U>> 

而反序列化方法看起来类似于这样的:

 public Map<T, U> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!json.isJsonObject()) { return null; } JsonObject jsonObject = json.getAsJsonObject(); Set<Entry<String, JsonElement>> jsonEntrySet = jsonObject.entrySet(); Map<T, U> deserializedMap = new HashMap<T, U>(); for (Entry<java.lang.String, JsonElement> entry : jsonEntrySet) { try { U value = context.deserialize(entry.getValue(), getMyType()); deserializedMap.put((T) entry.getKey(), value); } catch (Exception ex) { logger.info("Could not deserialize map.", ex); } } return deserializedMap; } 

与这个解决方案,是我的地图的关键总是类型“字符串”。 但是通过引用一些东西,可以使其具有通用性。 另外,我需要说的是,值的类应该在构造函数中传递。 所以在我的代码中的方法getMyType()返回的是在构造函数中传递的Map的值的类型。

你可以参考这篇文章如何编写一个自定义JSON解串器为Gson? 以了解更多关于定制解串器的信息。

  HashMap<String, String> jsonToMap(String JsonDetectionString) throws JSONException { HashMap<String, String> map = new HashMap<String, String>(); Gson gson = new Gson(); map = (HashMap<String, String>) gson.fromJson(JsonDetectionString, map.getClass()); return map; } 

JSONObject通常在内部使用HashMap来存储数据。 所以,你可以在你的代码中使用它作为Map。

例,

 JSONObject obj = JSONObject.fromObject(strRepresentation); Iterator i = obj.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = (Map.Entry)i.next(); System.out.println("Key: " + e.getKey()); System.out.println("Value: " + e.getValue()); } 

我用这个代码:

 Gson gson = new Gson(); HashMap<String, Object> fields = gson.fromJson(json, HashMap.class);