我是靠谱客的博主 忧心蚂蚁,最近开发中收集的这篇文章主要介绍Gson转Map结果int类型变为Double,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

用gson将string反序列化为Map时,int类型变成了double类型。

原因分析

  new Gson().fromJson("{"aid":123,"aa":11.0}", Map.class); // 结果为{"aid":123.0,"aa":11.0}

通过看gson解析过程,gson通过TypeAdapter的read方法来读取string的值并转化为对象:

public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
        boolean isEmpty = true;
        boolean oldLenient = reader.isLenient();
        reader.setLenient(true);

        TypeAdapter typeAdapter;
        try {
            try {
                reader.peek();
                isEmpty = false;
                TypeToken<T> typeToken = TypeToken.get(typeOfT);
                typeAdapter = this.getAdapter(typeToken);
                T object = typeAdapter.read(reader);
                Object var8 = object;
                return var8;
            } catch (EOFException var15) {
                if (!isEmpty) {
                    throw new JsonSyntaxException(var15);
                }
            } catch (IllegalStateException var16) {
                throw new JsonSyntaxException(var16);
            } catch (IOException var17) {
                throw new JsonSyntaxException(var17);
            } catch (AssertionError var18) {
                throw new AssertionError("AssertionError (GSON 2.8.5): " + var18.getMessage(), var18);
            }

            typeAdapter = null;
        } finally {
            reader.setLenient(oldLenient);
        }

        return typeAdapter;
    }

而TypeAdapter的类型通过TypeToken获取,所有TypeAdapter存放在gson对下的factories成员变量中,在转换时指定转换类型为Map.class,key和value默认为Object类型,所以开始获取的TypeAdapter为MapTypeAdapterFactory.Adapter类型

Iterator var7 = this.factories.iterator();

                    TypeAdapter candidate;
                    do {
                        if (!var7.hasNext()) {
                            throw new IllegalArgumentException("GSON (2.8.5) cannot handle " + type);
                        }

                        TypeAdapterFactory factory = (TypeAdapterFactory)var7.next();
                        candidate = factory.create(this, type);
                    } while(candidate == null);

                    call.setDelegate(candidate);
                    this.typeTokenCache.put(type, candidate);
                    TypeAdapter var10 = candidate;
                    return var10;

其value对应的TypeAdapter为ObjectTypeAdapter,而对于NUMBER类型的数据均会识别为double类型。

public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        switch(token) {
        case BEGIN_ARRAY:
            List<Object> list = new ArrayList();
            in.beginArray();

            while(in.hasNext()) {
                list.add(this.read(in));
            }

            in.endArray();
            return list;
        case BEGIN_OBJECT:
            Map<String, Object> map = new LinkedTreeMap();
            in.beginObject();

            while(in.hasNext()) {
                map.put(in.nextName(), this.read(in));
            }

            in.endObject();
            return map;
        case STRING:
            return in.nextString();
        case NUMBER:
            return in.nextDouble();
        case BOOLEAN:
            return in.nextBoolean();
        case NULL:
            in.nextNull();
            return null;
        default:
            throw new IllegalStateException();
        }
    }

解决方案

重新定义一个TypeAdapter期望来覆盖ObjectTypeAdapter,实现同现有的ObjectTypeAdapter,但是修改Number解析:
    case NUMBER:
                String numberStr = in.nextString();
                //返回的numberStr不会为null
                if (numberStr.contains(".") || numberStr.contains("e")
                        || numberStr.contains("E")) {
                    return Double.parseDouble(numberStr);
                }
                return Long.parseLong(numberStr);

注册到gson对象中如下:

new GsonBuilder().registerTypeAdapterFactory(ObjectTypeAdapter.FACTORY).create();

运行结果还是将int转换为了double类型。原因是register后的typeAdapter被add到factory的后面,而在查找typeAdater时从前往后遍历,还是找到了之前的ObjectTypeAdapter。

重新定义一个新的类型(gson默认没有的类型)确保查找时会找到创建的adpter:

public final class ObjectTypeAdapter extends TypeAdapter<Object> {

    private static final Gson gson = new Gson();
    private TypeAdapter objectTypeAdapter = gson.getAdapter(Object.class);

    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        switch(token) {
            case BEGIN_ARRAY:
                List<Object> list = new ArrayList();
                in.beginArray();

                while(in.hasNext()) {
                    list.add(this.read(in));
                }

                in.endArray();
                return list;
            case BEGIN_OBJECT:
                Map<String, Object> map = new LinkedTreeMap();
                in.beginObject();

                while(in.hasNext()) {
                    map.put(in.nextName(), this.read(in));
                }

                in.endObject();
                return map;
            case STRING:
                return in.nextString();
            case NUMBER:
                String numberStr = in.nextString();
                //返回的numberStr不会为null
                if (numberStr.contains(".") || numberStr.contains("e")
                        || numberStr.contains("E")) {
                    return Double.parseDouble(numberStr);
                }
                return Long.parseLong(numberStr);
            case BOOLEAN:
                return in.nextBoolean();
            case NULL:
                in.nextNull();
                return null;
            default:
                throw new IllegalStateException();
        }
    }

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

注册并调用如下,结果成功。

Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<Map<String, Object>>(){}.getType(), new ObjectTypeAdapter()).serializeNulls().create();
         gson.fromJson("{"aid":123,"aa":11.0}", new TypeToken<Map<String, Object>>(){}.getType());

最后

以上就是忧心蚂蚁为你收集整理的Gson转Map结果int类型变为Double的全部内容,希望文章能够帮你解决Gson转Map结果int类型变为Double所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部