首页 文章

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

提问于
浏览
242

我正在从服务器请求数据,该服务器以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模块 .

16 回答

  • 24

    我用过这段代码:

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

    干得好:

    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);
    
  • 98

    此代码有效:

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

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

    我的yaml反序列化器的工作方式,它默认JSON对象为 Map<String, Object> ,当你没有't specify a type, but gson doesn'似乎这样做 . 幸运的是,您可以使用自定义反序列化器来完成它 .

    我使用下面的反序列化器自然地反序列化任何东西,默认 JsonObjectMap<String, Object>JsonArray s到 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或一个整数或一个Long,并且可能更好,或者至少简化如果你可以获得BigDecimals,我相信这是默认的 .

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

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

    然后称之为:

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

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

  • -4

    更新新的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);
    
  • 0

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

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

    返回 com.google.gson.internal.LinkedTreeMap 类型为 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);
    

    并获得以下输出:

    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}
    
  • 2

    这是Kevin Dolan's answer的附录而不是一个完整的答案,但我无法从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());
      }
    }
    
  • 1
    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;
    
    }
    
  • 398

    我有完全相同的问题,最后到此为止 . 我有一个不同的方法似乎更简单(可能是更新版本的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");
    } ...
    

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

  • -1

    试试这个,它会奏效 . 我把它用于 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 替换为您的 class ,将 Integer 替换为您的 class .

  • -3

    这是我一直在使用的:

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

    从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));
    }
    
  • 3

    我已经克服了自定义JsonDeSerializer的类似问题 . 我试图让它有点通用但仍然不够 . 这是一个满足我需求的解决方案 .

    首先,您需要为Map对象实现一个新的JsonDeserializer .

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

    并且deserialize方法看起来类似于:

    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 's key is always of Type 1001845 . However by chaning some things someone can make it generic. In addition, i need to say, that the value'类应该在构造函数中传递 . 所以我的代码中的方法 getMyType() 返回Map的值的类型,它在构造函数中传递 .

    您可以参考这篇文章How do I write a custom JSON deserializer for Gson?,以了解有关自定义反序列化器的更多信息 .

  • 75

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

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

    You can use this class instead :) (处理偶数列表,嵌套列表和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 string to hashmap 使用此:

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

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

相关问题