Как я могу преобразовать JSON в HashMap с помощью Gson? - PullRequest
260 голосов
/ 06 мая 2010

Я запрашиваю данные с сервера, который возвращает данные в формате 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 ]

425 голосов
/ 11 апреля 2013

Вот, пожалуйста:

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);
104 голосов
/ 06 сентября 2012

Этот код работает:

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());
76 голосов
/ 26 января 2011

Я знаю, что это довольно старый вопрос, но я искал решение для общей десериализации вложенного JSON в Map<String, Object> и ничего не нашел.

Как работает мой десериализатор yaml, он по умолчанию устанавливает для объектов JSON значение Map<String, Object>, когда вы не указываете тип, но, похоже, gson этого не делает. К счастью, вы можете сделать это с помощью специального десериализатора.

Я использовал следующий десериализатор для естественной десериализации чего-либо, по умолчанию от JsonObject с до Map<String, Object> и от JsonArray с до 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, поскольку оно есть в большинстве других полуструктурированных библиотек сериализации ...

26 голосов
/ 12 сентября 2016

В Google Gson 2.7 (возможно, и в более ранних версиях, но я тестировал текущую версию 2.7) это так просто:

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

Возвращает Map типа com.google.gson.internal.LinkedTreeMap и рекурсивно работает с вложенными объектами, массивами и т. Д.

Я запустил пример 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}
24 голосов
/ 12 декабря 2013

Обновление для новой библиотеки Gson:
Теперь вы можете напрямую анализировать вложенный Json в Map, но вы должны знать, что если вы попытаетесь проанализировать Json для типа Map<String, Object>: это вызовет исключение. Чтобы это исправить, просто объявите результат как LinkedTreeMap type. Пример ниже:

String nestedJSON = "{"id":"1","message":"web_didload","content":{"success":1}};
Gson gson = new Gson();
LinkedTreeMap result = gson.fromJson(nestedJSON , LinkedTreeMap.class);
12 голосов
/ 09 сентября 2014

У меня был точно такой же вопрос, и я оказался здесь. У меня был другой подход, который кажется намного проще (может быть, новые версии 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);

1010 * выходы *

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

Вы можете динамически проверять использование instanceof при навигации по вашему jsonObject. Что-то вроде

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");
} ...

Это работает для меня, поэтому оно должно работать для вас; -)

3 голосов
/ 01 марта 2018

Ниже поддерживается 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 голосов
/ 14 сентября 2012

Попробуйте, это будет работать. Я использовал его для 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 на свой класс и Целое число на свой класс ключей.

2 голосов
/ 10 ноября 2011

Вот что я использовал:

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;
}
1 голос
/ 01 июля 2018

Вместо этого вы можете использовать этот класс:) (обрабатывает четные списки, вложенные списки и 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)) ;
...