GSON转换将Long类型转换Double导致精度丢失的问题排查

问题描述

项目中同步订单时发现一个问题,同一条的数据,order_id和item_id为Long类型,在同步时,数值变了。比如原本是6930414387088791188变成了69304143870884512001。

问题排查

经过排查发现http请求的返回参数是正常的,问题出现在客户端调用接口得到结果后,在进行json转换时,出现问题。项目中使用的gson作为json序列化和反序列化的工具。
转换代码如下:

Result result = JsonUtil.jsonToObject(httpResult.getBody(), Result.class);
List<OrderResponse> list =JsonUtil.jsonToList(JsonUtil.objectToJson(result), OrderResponse.class);

这个转换,第一步会使用gson默认的object转换:将数值类型转换成了Double类型。第二步再转换为指定类型时,数值就变了。
查看源码发现,只要是源数据是数值类型,在不指定类型的情况进行转换时,会使用gson默认的转换ObjectTypeAdapter,将所有数值型转换为Double,当源数据的Long型长度为19位(超过16位),丢失了精度,导致数据发生了变化。
在这里插入图片描述

解决方案

  1. **(推荐)**转换时制定好类型,不用gson默认的转换。转换方法如下:
    返回类定义如下:
public class ResponseList<T> {
	private String code;//状态码
    private String msg;//处理消息
    private List<T> data;
    
    ...
}

JsonUtil中转换方法如下:

public static <T> T fromJson(String json, Class<T> clazz, Class type) {
    if (StringUtils.isBlank(json)) {
        return null;
    }
    Type objectType = type(clazz, type);
    return gson.fromJson(json, objectType);
}

private static ParameterizedType type(final Class raw, final Type... args) {
    return new ParameterizedType() {
        public Type getRawType() {
            return raw;
        }

        public Type[] getActualTypeArguments() {
            return args;
        }

        public Type getOwnerType() {
            return null;
        }
    };
}

调用http结果后json转实体如下:

ResponseList<OrderResponse> resultResponse = JsonUtil.fromJson(httpResult.getBody(), ResponseList.class, OrderResponse.class);
  1. 如果继续想使用gson默认的转换,升级gson版本>=2.8.9,设置默认的转换策略,用BigDecimal接收,亲测可用
    升级gson版本至2.8.9以上
 <dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.9</version>
</dependency>
public class JsonUtil {

   private static Gson gson = new Gson();

	static {
       GsonBuilder gsonBuilder = new GsonBuilder();
       gsonBuilder.setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL);
       gson = gsonBuilder.create();
   }

}

如果您对技术有兴趣,友好交流,可以加v进技术群一起沟通,v:zzs1067632338,备注csdn即可

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值