Как я могу конвертировать JSON в HashMap с помощью Gson?
я запрашиваю данные с сервера, который возвращает данные в формате JSON. Приведение хэш-карты в 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 ответов:
вот так:
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);
этот код работает:
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 в A
Map<String, Object>и ничего не нашел.как работает мой десериализатор yaml, он по умолчанию использует объекты JSON в
Map<String, Object>когда вы не указываете тип, но gson, похоже, этого не делает. К счастью, вы можете сделать это с пользовательский десериализатор.я использовал следующий десериализатор, чтобы естественно десериализовать что-либо, по умолчанию
JsonObjectьMap<String, Object>иJsonArrayь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метод предназначен для того, чтобы убедиться, что вы когда-либо получаете только двойное или целое число или длинное, и, вероятно, может быть лучше или, по крайней мере, упрощено, если вы в порядке с получением BigDecimals, что я считаю по умолчанию.вы можете зарегистрировать этот адаптер как:
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer()); Gson gson = gsonBuilder.create();а потом назовем это так:
Object natural = gson.fromJson(source, Object.class);Я не уверен, почему это не поведение по умолчанию в gson, так как оно находится в большинстве других полуструктурированных библиотек сериализации...
обновление для нового 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);
С google Gson 2.7 (вероятно, более ранние версии тоже, но я тестировал с текущей версией 2.7) это так же просто, как:
Map map = gson.fromJson(jsonString, Map.class);который возвращает a
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}
у меня был точно такой же вопрос и попал сюда. У меня был другой подход, который кажется намного проще (может быть, более новые версии 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"); } ...он работает для меня, поэтому он должен работать для вас ; -)
попробуйте это, это работает. Я использовал его для 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 в свой класс и целое к вашему ключевому классу.
вот что я использую:
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; }
ниже поддерживается начиная с 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)); }
Я преодолел аналогичную проблему с пользовательским JsonDeSerializer. Я попытался сделать его немного общим, но все еще недостаточно. Это решение, хотя и соответствует моим потребностям.
прежде всего вам нужно реализовать новый JsonDeserializer для объектов карты.
public class MapDeserializer<T, U> implements JsonDeserializer<Map<T, U>>и метод десериализации будет выглядеть примерно так:
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; }con с этим решением заключается в том, что ключ моей карты всегда имеет тип "String". Однако, читая некоторые вещи, кто-то может сделайте его общим. Кроме того, мне нужно сказать, что класс значения должен быть передан в конструкторе. Так что метод
getMyType()в моем коде возвращает тип значений карты, который был передан в конструкторе.вы можете ссылаться на этот пост Как написать пользовательский десериализатор JSON для Gson? для того, чтобы узнать больше о пользовательских десериализаторы.
вот один лайнер, который сделает это:
HashMap<String, Object> myMap = gson.fromJson(yourJson, new TypeToken<HashMap<String, Object>>(){}.getType());
вы можете использовать этот класс :) (обрабатывает даже списки, вложенные списки и 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)) ;
Это скорее дополнение к ответ Кевина Долана чем полный ответ, но у меня возникли проблемы с извлечением типа из числа. Это мое решение:
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()); } }
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; }
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()); }
я использовал этот код:
Gson gson = new Gson(); HashMap<String, Object> fields = gson.fromJson(json, HashMap.class);
Comments