gson 将整型数据主动转成浮点型数据bug解决方案

2020-06-19  本文已影响0人  gooddaytoyou

描述

通过google的gson 将json String串转成 Map时,里面如果有Long或Int类型会被转成浮点型。

原始数据

{"Param":{"stringtype":"This is String","timestamp":1597817205000,"arr":[12334,2323,334344],"double":7.0},"Type":"/api/test/getName"}

代码

String json = "{\"Param\":{\"stringtype\":\"This is String\",\"timestamp\":1597817205000,\"arr\":[12334,2323,334344],\"double\":7.0},\"Type\":\"/api/test/getName\"}";
    
Gson gson = new Gson();

Map<String, Object> objectMap = gson.fromJson(json, new TypeToken<Map<String, Object>>() {
    }.getType());

System.out.println(objectMap);

运行结果

{Param={stringtype=This is String, timestamp=1.597817205E12, arr=[12334.0, 2323.0, 334344.0], double=7.0}, Type=/api/test/getName}

我们可以看到timestamp=1.597817205E12, arr=[12334.0, 2323.0, 334344.0]数据格式变了。

为什么会出现整型数据被转成浮点型数据?

我们结合网上的提示及原码,定位到了ObjectTypeAdapter。

ObjectTypeAdapter#read(JsonReader in)
                    ...
                    //这里,所有的NUMBER都当成Double来处理
                     case NUMBER:
                        return in.nextDouble();
                    ....

解决方案

方案一 重写ObjectTypeAdapter
CustomizedObjectTypeAdapter#read(JsonReader in)
                    ...
    
                     case NUMBER:
                       //return in.nextDouble();
                        String n = in.nextString();
                        if (n.indexOf('.') != -1) {
                            return Double.parseDouble(n);
                        }
                        return Long.parseLong(n);
                    ....`

自定义的CustomizedObjectTypeAdapter类

class CustomizedObjectTypeAdapter extends TypeAdapter<Object> {

    private final TypeAdapter<Object> delegate = new Gson().getAdapter(Object.class);

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        delegate.write(out, value);
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        switch (token) {
            case BEGIN_ARRAY:
                List<Object> list = new ArrayList<Object>();
                in.beginArray();
                while (in.hasNext()) {
                    list.add(read(in));
                }
                in.endArray();
                return list;

            case BEGIN_OBJECT:
                Map<String, Object> map = new LinkedTreeMap<String, Object>();
                in.beginObject();
                while (in.hasNext()) {
                    map.put(in.nextName(), read(in));
                }
                in.endObject();
                return map;

            case STRING:
                return in.nextString();

            case NUMBER:
                //return in.nextDouble();
                String n = in.nextString();
                if (n.indexOf('.') != -1) {
                    return Double.parseDouble(n);
                }
                return Long.parseLong(n);

            case BOOLEAN:
                return in.nextBoolean();

            case NULL:
                in.nextNull();
                return null;

            default:
                throw new IllegalStateException();
        }
    }
}

调用

String json = "{\"Param\":{\"stringtype\":\"This is String\",\"timestamp\":1597817205000,\"arr\":[12334,2323,334344],\"double\":7.0},\"Type\":\"/api/test/getName\"}";
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(new TypeToken<Map<String, Object>>() {
        }.getType(), new CustomizedObjectTypeAdapter());
Gson gson = gsonBuilder.create();

Map<String, Object> objectMap = gson.fromJson(json, new TypeToken<Map<String, Object>>() {
        }.getType());

System.out.println(objectMap);

运行结果

{Param={stringtype=This is String, timestamp=1597817205000, arr=[12334, 2323, 334344], double=7.0}, Type=/api/test/getName}

可以看到整型数据保持不变。

方案二 使用Jackson

如果你使用jackson框架来解析json,上面的问题就不存在。
相关调用

String json = "{\"Param\":{\"stringtype\":\"This is String\",\"timestamp\":1597817205000,\"arr\":[12334,2323,334344],\"double\":7.0},\"Type\":\"/api/test/getName\"}";

TypeReference<Map<String, Object>> typeRef
                = new TypeReference<Map<String, Object>>() {};
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> objectMap = null;
try {
    objectMap = mapper.readValue(json, typeRef);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

System.out.println(objectMap);

运行结果

{Param={stringtype=This is String, timestamp=1597817205000, arr=[12334, 2323, 334344], double=7.0}, Type=/api/test/getName}

相关参考

how-can-i-prevent-gson-from-converting-integers-to-doubles

上一篇下一篇

猜你喜欢

热点阅读