Comment convertir JSON en HashMap en utilisant Gson?

je demande des données à un serveur qui renvoie des données au format JSON. Lancer un HashMap dans JSON en faisant la demande n'était pas difficile mais l'autre façon semble être un peu délicate. La réponse de JSON ressemble à ceci:

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

de quelle façon serait-il le plus facile d'accéder à ces données? Je suis à l'aide de la GSON module.

229
demandé sur Mridang Agarwalla 2010-05-06 11:29:34

16 réponses

Ici, vous allez:

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);
372
répondu cherit 2018-08-16 16:33:48

ce code fonctionne:

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());
96
répondu Angel 2016-03-26 23:27:32

je sais qu'il s'agit d'une question assez ancienne, mais je cherchais une solution pour désérialiser généreusement emboîté JSON à un Map<String, Object> , et n'a rien trouvé.

la façon dont mon deserializer yaml fonctionne, il renvoie par défaut les objets JSON à Map<String, Object> quand vous ne spécifiez pas de type, mais gson ne semble pas faire cela. Heureusement, vous pouvez l'accomplir avec une coutume deserializer.

j'ai utilisé le désérialiseur suivant pour désérialiser naturellement n'importe quoi, défaut JsonObject s à Map<String, Object> et JsonArray s à Object[] s, où tous les enfants sont également desérialisé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;
  }
}

le désordre à l'intérieur de la méthode handlePrimitive est pour s'assurer que vous obtenez seulement un Double ou un entier ou un Long, et pourrait probablement être mieux, ou au moins simplifié si vous êtes d'accord avec l'obtention de BigDecimals, qui je crois est la valeur par défaut.

vous pouvez enregistrer cet adaptateur comme:

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

et appelez ça comme:

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

Je ne sais pas pourquoi ce n'est pas le comportement par défaut dans gson, puisque c'est le cas dans la plupart des autres bibliothèques de sérialisation semi-structurées...

75
répondu Kevin Dolan 2011-01-25 22:29:03

mise à jour pour la nouvelle Gson lib:

Vous pouvez maintenant analyser les JSON imbriqués pour les maps directement, mais vous devez être conscient au cas où vous essayeriez d'analyser les Json au type Map<String, Object> : cela soulèvera une exception. Pour corriger cela, il suffit de déclarer le résultat comme LinkedTreeMap type. Exemple ci-dessous:

String nestedJSON = "{"id":"1","message":"web_didload","content":{"success":1}};
Gson gson = new Gson();
LinkedTreeMap result = gson.fromJson(nestedJSON , LinkedTreeMap.class);
24
répondu Hoang Huu 2014-02-12 03:03:57

avec Gson 2.7 de google (probablement des versions plus anciennes aussi, mais j'ai testé avec la version actuelle 2.7) c'est aussi simple que:

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

qui renvoie un Map de type com.google.gson.internal.LinkedTreeMap et travaille récursivement sur des objets imbriqués, tableaux, etc.

j'ai exécuté L'exemple OP comme si (simplement remplacé double-avec simple-guillemets et enlevé les espaces):

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

et obtenu la sortie suivante:

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
répondu isapir 2016-09-12 06:01:31

j'ai eu exactement la même question et fini ici. J'ai eu une approche différente qui semble beaucoup plus simple (peut-être de nouvelles versions de gson?).

    Gson gson = new Gson();
    Map jsonObject = (Map) gson.fromJson(data, Object.class);

avec le json suivant

{
  "map-00": {
    "array-00": [
      "entry-00",
      "entry-01"
     ],
     "value": "entry-02"
   }
}

Le suivant

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

sorties

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

vous pouvez vérifier dynamiquement en utilisant instanceof lors de la navigation de votre jsonObject. Quelque chose comme

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

Cela fonctionne pour moi, donc cela doit fonctionner pour vous ;-)

10
répondu krico 2014-09-09 14:13:52

essayez ça, ça va marcher. Je l'ai utilisé pour table de hachage .

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

remplacer KioskStatusResource à votre classe et entier à votre classe clé.

3
répondu R4U 2012-09-21 08:59:12

voici ce que j'ai utilisé:

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;
}
2
répondu OZG 2011-11-10 14:42:39

ci-dessous est supporté depuis 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));
}
2
répondu Leon 2018-03-01 06:35:18

j'ai surmonté un problème similaire avec un Jsondeserializer personnalisé. J'ai essayé de le rendre un peu générique mais pas encore assez. C'est une solution mais qui correspond à mes besoins.

tout d'abord, vous devez mettre en œuvre un nouveau JsonDeserializer pour les objets de carte.

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

et la méthode deserialize ressemblera à ceci:

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

le problème avec cette solution, c'est que la clé de ma carte est toujours de Type"String". Cependant, en chantant certaines choses, quelqu'un peut les rendre génériques. En outre, je dois dire, que la classe de la valeur doit être passée dans le constructeur. Ainsi la méthode getMyType() dans mon code renvoie le type des valeurs de la carte, qui a été passé dans le constructeur.

Vous pouvez faire référence à ce post Comment puis-je écrire un JSON personnalisé deserializer pour Gson? pour en savoir plus sur les désérialiseurs personnalisés.

1
répondu nikkatsa 2017-05-23 12:02:50

Voici une doublure qui le fera:

HashMap<String, Object> myMap =
   gson.fromJson(yourJson, new TypeToken<HashMap<String, Object>>(){}.getType());
1
répondu Ab_ 2018-04-12 16:00:38

vous pouvez utiliser cette classe à la place de:) (gère même les listes , les listes imbriquées et 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;
    }
}

pour convertir votre chaîne JSON en hashmap utilisez ceci:

HashMap<String, Object> hashMap = new HashMap<>(Utility.jsonToMap(response)) ;
1
répondu Natesh bhat 2018-07-01 07:55:39

c'est plus un addenda à la réponse de Kevin Dolan qu'une réponse complète, mais j'avais de la difficulté à extraire le type du numéro. C'est ma solution:

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());
  }
}
0
répondu Luke Salamone 2018-10-06 01:26:14
 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
répondu user2918406 2017-09-21 19:38:49

JSONObject utilise typiquement HashMap en interne pour stocker les données. Vous pouvez donc L'utiliser comme Map dans votre code.

exemple,

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());
}
-3
répondu Phanindra 2010-05-06 09:49:01

j'ai utilisé ce code:

Gson gson = new Gson();
HashMap<String, Object> fields = gson.fromJson(json, HashMap.class);
-4
répondu mortalis 2015-04-21 16:48:46