2010-05-06 4 views
199

Я запрашиваю данные с сервера, который возвращает данные в формате JSON. Приведение HashMap в JSON при выполнении запроса не было сложным, но, наоборот, это немного сложно. Ответ JSON выглядит следующим образом:Как конвертировать JSON в HashMap с помощью Gson?

{ 
    "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.

+10

'Карта r esult = new Gson(). fromJson (json, Map.class); 'работает с gson 2.6.2. –

+1

как конвертировать назад? Я имею в виду от Карты до Json Array. –

ответ

325

Здесь вы идете

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

Работает как очарование! Благодаря! – curious1

+4

Хороший, но мне не нравится использовать 'TypeToken' - это неявное литье внутри. –

+0

@TitoCheriachan У меня есть аналогичный вопрос с Gson [здесь] (http://stackoverflow.com/questions/41029313/how-to-parse-json-into-a-map-using-gson). Я хотел посмотреть, сможешь ли ты мне помочь. У меня есть решение, но проблема в том, что он выглядит очень грязным, чтобы разобрать JSON на карту. – john

-3

JSONObject обычно использует HashMap для хранения данных. Таким образом, вы можете использовать его как карту в своем коде.

Пример,

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

Это из json-lib, а не gson! – Ammar

72

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

+2

Спасибо, это было действительно полезно. –

+1

... хотя я не совсем уверен, что делать теперь с Объектами, которые я возвращаю. Кажется, они не кастуют как String, хотя я знаю, что они строки –

+1

Aha! Трюк был вызовом десериализатора рекурсивно вместо вызова context.deserialize(). –

2

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

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

что такое parser.parse ?! – Ammar

+0

Это, вероятно, «новый com.google.gson.JsonParser(). Parse()» –

87

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

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

Это преобразует ints в float, прежде чем превратит их в строки, но будет работать для преобразования JSON в карты для целей сравнения. – louielouie

+0

Мне это очень помогло. Большое вам спасибо – Zac

+10

отлично работает для меня, но я изменил карту на «Map ', потому что если json - это не только строки, вы получаете ошибку –

3

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

+0

Это работало для меня после того, как HashMap выбрал исключение LinkedTreeMap. – newfivefour

1

Я преодолел аналогичную проблему с пользовательским JsonDeSerializer. Я попытался сделать его несколько родовым, но все еще недостаточно. Это решение, хотя это и соответствует моим потребностям.

Прежде всего вам необходимо реализовать новый JsonDeserializer для объектов Map.

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

Зэк с этим решением, является то, что ключ моей карты является всегда тип «String». Однако, перебирая некоторые вещи, кто-то может сделать это родовым. Кроме того, мне нужно сказать, что класс value должен быть передан в конструкторе. Таким образом, метод getMyType() в моем коде возвращает тип значений карты, который был передан в конструкторе.

Вы можете обратиться к этому сообщению How do I write a custom JSON deserializer for Gson?, чтобы узнать больше о пользовательских десериализаторах.

23

Обновления для нового Gson Lib:
Теперь можно разобрать вложенный JSon к карте напрямую, но вы должны знать, в случае, если вы пытаетесь разобрать 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

Где я могу импортировать LinkedTreeMap? Я не могу найти его в коде Gson. – HelpMeStackOverflowMyOnlyHope

+0

Как я помню, LinkedTreeMap определен в новом Gson lib. Вы можете здесь посмотреть: https://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java? r = 1204 –

+1

Для меня это работает также с 'Map result = gson.fromJson (json, Map.class);'. Использование gson 2.6.2. –

9

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

Вы можете динамически проверки с помощью 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

Я использовал этот код:

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

Это дает мне предупреждение без предупреждения. – Line

18

С Gson Google в 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} 
-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; 

} 
1

Ниже приводится поддерживается с 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)); 
}