关于java:如何使用Gson将JSON转换为HashMap?

How can I convert JSON to a HashMap using Gson?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
   "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模块。


干得好:

1
2
3
4
5
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);


此代码有效:

1
2
3
4
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,但一无所获。

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

我使用下面的反序列化器来自然地反序列化任何东西,将JsonObject s默认为MapJsonArray s到Object[] s,其中所有的孩子都被类似地反序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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或整数或一个Long,并且可能更好,或者至少简化如果你可以获得BigDecimals,我相信这是默认的。

您可以注册此适配器,如:

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

然后把它称为:

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

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


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

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

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

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

1
2
3
4
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);

得到以下输出:

1
2
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 lib:
您现在可以直接将嵌套的Json解析为Map,但是您应该知道如果您尝试将Json解析为Map类型:它将引发异常。要解决此问题,只需将结果声明为LinkedTreeMap类型。示例如下:

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


我有完全相同的问题,最后来到这里。我有一个看起来更简单的不同方法(也许是更新版本的gson?)。

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

以下是json

1
2
3
4
5
6
7
8
9
{
 "map-00": {
   "array-00": [
     "entry-00",
     "entry-01"
     ],
    "value":"entry-02"
   }
}

下列

1
2
3
4
5
6
7
    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);

输出

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

您可以在导航jsonObject时使用instanceof动态检查。就像是

1
2
3
4
5
6
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 2.8.0开始支持以下版本

1
2
3
4
5
6
7
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));
}

试试这个,它会奏效。我把它用于Hashtable。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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替换为您的密钥类。


这是我一直在使用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。

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

并且反序列化方法看起来类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
    }

与此解决方案一致的是,我的Map的键始终是Type"String"。然而,通过chaning某些东西,有人可以使它成为通用的。另外,我需要说,值的类应该在构造函数中传递。所以我的代码中的方法getMyType()返回Map的值的类型,它在构造函数中传递。

您可以参考这篇文章如何为Gson编写自定义JSON反序列化器?以了解有关自定义反序列化器的更多信息。


这是一个可以做到这一点的单线程:

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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,请使用以下命令:

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

这是对Kevin Dolan的答案的补充,而不是一个完整的答案,但我无法从Number中提取类型。这是我的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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());
  }
}

1
2
3
4
5
6
7
8
9
10
 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;

}

我用过这段代码:

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


JSONObject通常在内部使用HashMap来存储数据。因此,您可以在代码中将其用作Map。

例,

1
2
3
4
5
6
7
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());
}