如何使用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模块。

375743 次浏览

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());
}

我知道这是一个相当老的问题,但我正在寻找一种解决方案,将嵌套的JSON反序列化为Map<String, Object>,但一无所获。

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

我使用下面的反序列化器来自然地反序列化任何东西,默认JsonObjects为Map<String, Object>JsonArrays为Object[]s,其中所有的子对象都类似地反序列化。

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的默认行为,因为在大多数其他半结构化序列化库中都是这样…

以下是我一直在用的:

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;
}

这段代码工作:

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

试试这个,它会起作用的。我将它用于< em > Hashtable < / em >

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;
}

< em > KioskStatusResource < / em >替换为你的类,将< em >整数< / em >替换为你的键类。

我已经克服了一个自定义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值的类型,该类型被传递到构造函数中。

你可以参考这个帖子如何为Gson编写自定义JSON反序列化?来学习更多关于自定义反序列化器的知识。

给你:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;


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

更新新的Gson lib:
你现在可以直接将嵌套的Json解析为Map,但你应该注意,如果你试图将Json解析为Map<String, Object>类型:它将引发异常。要解决这个问题,只需将结果声明为LinkedTreeMap类型。在下面的例子:< / p >

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

我也有同样的问题,结果来了这里。我有一个不同的方法,看起来简单得多(也许是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");
} ...

它对我有效,所以它一定对你有效;-)

我使用了下面的代码:

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

使用谷歌的Gson 2.7(可能是更早的版本,但我测试了当前的2.7版本),它很简单:

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

返回类型为com.google.gson.internal.LinkedTreeMapMap,并在嵌套对象、数组等上递归工作。

我像这样运行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}
 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;


}

从gson 2.8.0开始支持以下内容

public static Type getMapType(Class keyType, Class valueType){
return TypeToken.getParameterized(HashMap.class, keyType, valueType).getType();
}


public static  <K,V> HashMap<K,V> fromMap(String json, Class<K> keyType, Class<V> valueType){
return gson.fromJson(json, getMapType(keyType,valueType));
}

下面的一行代码就可以做到这一点:

HashMap<String, Object> myMap =
gson.fromJson(yourJson, new TypeToken<HashMap<String, Object>>(){}.getType());

你可以使用这个类代替:)(处理偶数列表,嵌套列表和json)

public class Utility {


public static Map<String, Object> jsonToMap(Object json) throws JSONException {


if(json instanceof JSONObject)
return _jsonToMap_((JSONObject)json) ;


else if (json instanceof String)
{
JSONObject jsonObject = new JSONObject((String)json) ;
return _jsonToMap_(jsonObject) ;
}
return null ;
}




private static Map<String, Object> _jsonToMap_(JSONObject json) throws JSONException {
Map<String, Object> retMap = new HashMap<String, Object>();


if(json != JSONObject.NULL) {
retMap = toMap(json);
}
return retMap;
}




private static Map<String, Object> toMap(JSONObject object) throws JSONException {
Map<String, Object> map = new HashMap<String, Object>();


Iterator<String> keysItr = object.keys();
while(keysItr.hasNext()) {
String key = keysItr.next();
Object value = object.get(key);


if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}


else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
map.put(key, value);
}
return map;
}




public static List<Object> toList(JSONArray array) throws JSONException {
List<Object> list = new ArrayList<Object>();
for(int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}


else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
list.add(value);
}
return list;
}
}

要转换你的JSON字符串到hashmap,使用这个:

HashMap<String, Object> hashMap = new HashMap<>(Utility.jsonToMap(response)) ;

这更像是凯文·多兰的回答是的补充,而不是完整的答案,但我在从Number中提取类型时遇到了麻烦。这是我的解决方案:

private Object handlePrimitive(JsonPrimitive json) {
if(json.isBoolean()) {
return json.getAsBoolean();
} else if(json.isString())
return json.getAsString();
}


Number num = element.getAsNumber();


if(num instanceof Integer){
map.put(fieldName, num.intValue());
} else if(num instanceof Long){
map.put(fieldName, num.longValue());
} else if(num instanceof Float){
map.put(fieldName, num.floatValue());
} else {    // Double
map.put(fieldName, num.doubleValue());
}
}