How can I convert JSON to a HashMap using Gson?

前端 未结 16 2572
臣服心动
臣服心动 2020-11-22 05:14

I\'m requesting data from a server which returns data in the JSON format. Casting a HashMap into JSON when making the request wasn\'t hard at all but the other way seems to

16条回答
  •  萌比男神i
    2020-11-22 05:58

    I know this is a fairly old question, but I was searching for a solution to generically deserialize nested JSON to a Map, and found nothing.

    The way my yaml deserializer works, it defaults JSON objects to Map when you don't specify a type, but gson doesn't seem to do this. Luckily you can accomplish it with a custom deserializer.

    I used the following deserializer to naturally deserialize anything, defaulting JsonObjects to Map and JsonArrays to Object[]s, where all the children are similarly deserialized.

    private static class NaturalDeserializer implements JsonDeserializer {
      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 map = new HashMap();
        for(Map.Entry entry : json.entrySet())
          map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
        return map;
      }
    }
    
    
    

    The messiness inside the handlePrimitive method is for making sure you only ever get a Double or an Integer or a Long, and probably could be better, or at least simplified if you're okay with getting BigDecimals, which I believe is the default.

    You can register this adapter like:

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

    And then call it like:

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

    I'm not sure why this is not the default behavior in gson, since it is in most other semi-structured serialization libraries...

    提交回复
    热议问题