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

Mri*_*lla 270 java json dictionary hashmap gson

我正在从服务器请求数据,该服务器以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"
}
Run Code Online (Sandbox Code Playgroud)

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

che*_*rit 446

干得好:

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);
Run Code Online (Sandbox Code Playgroud)

  • 好的,但我不喜欢使用`TypeToken` - 它在内部进行隐式转换. (6认同)
  • `new Gson().fromJson(jsonData, new TypeToken&lt;Map&lt;String, Integer&gt;&gt;(){}.getType());` 正在转换为 `Double` 而不是 `Integer`? (3认同)
  • @EvanKairuz 不,不是。应该是 `{"k1":"apple","k2":"orange"}` (2认同)

小智 108

此代码有效:

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());
Run Code Online (Sandbox Code Playgroud)

  • 对我很有用,但是我把地图更改为`Map <String,Object>`因为如果json不仅是字符串你会得到一个错误 (11认同)
  • 这给人一种错误的印象.参数化类型的正确解决方案是`TypeToken`. (4认同)
  • 这将在将整数转换为字符串之前将其转换为浮点数,但它可以将 JSON 转换为映射以进行比较。 (3认同)

Kev*_*lan 76

我知道这是一个相当古老的问题,但我正在寻找一种解决方案,通常将嵌套的JSON反序列化为a 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

handlePrimitive方法内部的混乱是为了确保你只获得一个Double或一个整数或一个Long,并且可能更好,或者至少可以简化,如果你可以获得BigDecimals,我相信这是默认的.

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

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();
Run Code Online (Sandbox Code Playgroud)

然后把它称为:

Object natural = gson.fromJson(source, Object.class);
Run Code Online (Sandbox Code Playgroud)

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

  • Gson现在默认似乎具有Kevin Dolan在其代码片段中的行为. (5认同)

isa*_*pir 29

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

Map map = gson.fromJson(jsonString, Map.class);
Run Code Online (Sandbox Code Playgroud)

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

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

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);
Run Code Online (Sandbox Code Playgroud)

得到以下输出:

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}
Run Code Online (Sandbox Code Playgroud)


Hoa*_*Huu 24

更新新的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);
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,有效的(感谢上面的建议!)是转换嵌套 ```HashMap&lt;String, Object&gt;``` (因为 TypeToken 技巧在嵌套上对我不起作用)是将它们作为 LinkedTreeMap 对象返回。从那里我只是迭代 LinkedTreeMap 键并在循环中填充新的 HashMap,因为它们具有相同的方法。不知道为什么你不能直接施法,但满足了我的需要。 (2认同)

kri*_*ico 12

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

    Gson gson = new Gson();
    Map jsonObject = (Map) gson.fromJson(data, Object.class);
Run Code Online (Sandbox Code Playgroud)

以下是json

{
  "map-00": {
    "array-00": [
      "entry-00",
      "entry-01"
     ],
     "value": "entry-02"
   }
}
Run Code Online (Sandbox Code Playgroud)

下列

    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);
Run Code Online (Sandbox Code Playgroud)

输出

map-00.array-00[0]= entry-00
map-00.array-00[1]= entry-01
map-00.value = entry-02
Run Code Online (Sandbox Code Playgroud)

您可以在导航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");
} ...
Run Code Online (Sandbox Code Playgroud)

它对我有用,所以它必须适合你;-)


Leo*_*eon 5

自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));
}
Run Code Online (Sandbox Code Playgroud)