How can I prevent gson from converting integers to doubles

前端 未结 6 672
再見小時候
再見小時候 2020-12-05 07:37

I\'ve got integers in my json, and I do not want gson to convert them to doubles. The following does not work:

@Test
public void keepsIntsAsIs(){
    String          


        
6条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-05 08:28

    1) You have to create custom JsonDeserializer and not JsonSerializer like in your question.

    2) I don't think this behavior comes from Double deserializer. it is more like json object/map problem

    Here is from source code:

    case NUMBER:
          return in.nextDouble();
    

    So you can try approach with custom deserializer for Map (or some more generic map if you want) :

    public static class MapDeserializerDoubleAsIntFix implements JsonDeserializer>{
    
        @Override  @SuppressWarnings("unchecked")
        public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            return (Map) read(json);
        }
    
        public Object read(JsonElement in) {
    
            if(in.isJsonArray()){
                List list = new ArrayList();
                JsonArray arr = in.getAsJsonArray();
                for (JsonElement anArr : arr) {
                    list.add(read(anArr));
                }
                return list;
            }else if(in.isJsonObject()){
                Map map = new LinkedTreeMap();
                JsonObject obj = in.getAsJsonObject();
                Set> entitySet = obj.entrySet();
                for(Map.Entry entry: entitySet){
                    map.put(entry.getKey(), read(entry.getValue()));
                }
                return map;
            }else if( in.isJsonPrimitive()){
                JsonPrimitive prim = in.getAsJsonPrimitive();
                if(prim.isBoolean()){
                    return prim.getAsBoolean();
                }else if(prim.isString()){
                    return prim.getAsString();
                }else if(prim.isNumber()){
    
                    Number num = prim.getAsNumber();
                    // here you can handle double int/long values
                    // and return any type you want
                    // this solution will transform 3.0 float to long values
                    if(Math.ceil(num.doubleValue())  == num.longValue())
                       return num.longValue();
                    else{
                        return num.doubleValue();
                    }
               }
            }
            return null;
        }
    }
    
    
    

    To use it you will have to give proper TypeToken to registerTypeAdapter and gson.fromJson function:

    String json="[{\"id\":1,\"quantity\":2,\"name\":\"apple\"}, {\"id\":3,\"quantity\":4,\"name\":\"orange\"}]";
    
    GsonBuilder gsonBuilder = new GsonBuilder();
    
    gsonBuilder.registerTypeAdapter(new TypeToken>(){}.getType(),  new MapDeserializerDoubleAsIntFix());
    
    Gson gson = gsonBuilder.create();
    List> l = gson.fromJson(json, new TypeToken>>(){}.getType() );
    
    for(Map item : l)
        System.out.println(item);
    
    String serialized = gson.toJson(l);
    System.out.println(serialized);
    

    Result:

    {id=1, quantity=2, name=apple}
    {id=3, quantity=4, name=orange}
    Serialized back to: [{"id":1,"quantity":2,"name":"apple"},{"id":3,"quantity":4,"name":"orange"}]
    

    PS: It is just one more option you can try. Personally i feel like creating custom object for your json instead of List> is much cooler and easier to read way

    提交回复
    热议问题