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());
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值