gson 反序列化,整数变小数的终极解决方案

1.情景展示

使用gson进行反序列化(json转java对象)的时候,你可能会遇到明明key对应的值是整数,而进行反序列化后,却变成了小数(后面加上了.0)。

如何解决这个问题?

2.具体分析

准备工作

查看代码
/**
 * 数值类型实体类
 * @description: 包含整数和小数
 * @author: Marydon
 * @date: 2022-03-24 18:48
 * @version: 1.0
 * @email: marydon20170307@163.com
 */
public class Number {
    private byte b;
    private short s;
    private int i;
    private long l;
    private double d;
    private float f;
    private Byte B2;
    private Short S2;
    private Integer I2;
    private Long L2;
    private Double D2;
    private Float F2;
    private BigDecimal bd;
    private BigInteger gi;

    public byte getB() {
        return b;
    }

    public void setB(byte b) {
        this.b = b;
    }

    public short getS() {
        return s;
    }

    public void setS(short s) {
        this.s = s;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public long getL() {
        return l;
    }

    public void setL(long l) {
        this.l = l;
    }

    public double getD() {
        return d;
    }

    public void setD(double d) {
        this.d = d;
    }

    public float getF() {
        return f;
    }

    public void setF(float f) {
        this.f = f;
    }

    public Byte getB2() {
        return B2;
    }

    public void setB2(Byte b2) {
        B2 = b2;
    }

    public Short getS2() {
        return S2;
    }

    public void setS2(Short s2) {
        S2 = s2;
    }

    public Integer getI2() {
        return I2;
    }

    public void setI2(Integer i2) {
        I2 = i2;
    }

    public Long getL2() {
        return L2;
    }

    public void setL2(Long l2) {
        L2 = l2;
    }

    public Double getD2() {
        return D2;
    }

    public void setD2(Double d2) {
        D2 = d2;
    }

    public Float getF2() {
        return F2;
    }

    public void setF2(Float f2) {
        F2 = f2;
    }

    public BigDecimal getBd() {
        return bd;
    }

    public void setBd(BigDecimal bd) {
        this.bd = bd;
    }

    public BigInteger getGi() {
        return gi;
    }

    public void setGi(BigInteger gi) {
        this.gi = gi;
    }

    public Number(Byte b2, Short s2, Integer i2, Long l2, Double d2, Float f2) {
        B2 = b2;
        S2 = s2;
        I2 = i2;
        L2 = l2;
        D2 = d2;
        F2 = f2;
    }

    @Override
    public String toString() {
        return "Number{" +
                "b=" + b +
                ", s=" + s +
                ", i=" + i +
                ", l=" + l +
                ", d=" + d +
                ", f=" + f +
                ", B2=" + B2 +
                ", S2=" + S2 +
                ", I2=" + I2 +
                ", L2=" + L2 +
                ", D2=" + D2 +
                ", F2=" + F2 +
                ", bd=" + bd +
                ", gi=" + gi +
                '}';
    }
}

我们先来回顾一下,出现这种情况的具体使用场景。

现在,有这样一种需求:

要将json数组转变成List,Gson的实现语法如下:

new Gson().fromJson(json, new TypeToken<List<T>>(){}.getType());

以下三种调用方式,将会导致整数变小数:

Number number = new Number((byte)1, (short)2, 3, 4L, 5D, 6F);
List<Number> numbers = new ArrayList<>(1);
numbers.add(number);
String gsonStrs = new Gson().toJson(numbers);
System.out.println(gsonStrs);
// 错误方式一:不加泛型限制
List<Number> numberList = new Gson().fromJson(gsonStrs, new TypeToken<List>(){}.getType());
System.out.println(numberList);
// 错误方式二:使用反射
numberList = new Gson().fromJson(gsonStrs, new TypeToken<List<?>>(){}.getType());
System.out.println(numberList);

 

错误方式三:封装使用

List<Number> numberList = JsonUtils.toJavaBeansByGson(gsonStrs);
System.out.println(numberList);

执行结果如下: 

3.解决方案

前两种错误实现方式,一般人不会犯这样的错误。

问题在于第三种,有些让人猝不及防。

本来,我想着是,对Gson再进行一次封装,这样下次直接调用即可,不用再写那么长的代码了,结果就是:

弄巧成拙!

我们加上具体的泛型限制,再来看一下执行结果。

List<Number> numberList = new Gson().fromJson(gsonStrs, new TypeToken<List<Number>>(){}.getType());
System.out.println(numberList);

 

我们可以看到,这次是没有问题的。

方式一:List必须使用具体的实体类进行限制;

所以说,如果,想要使用通过gson将json数组转换成list实体类,list必须要指定具体的泛型类。

换句话说就是,不能再对gson将json数组转成list的方式进行二次封装。

如果像错误方式三那样封装使用的话,必须保证你的java实体类不包含数值类型属性,否则,将会全部转成小数Double类型。

方式二:重新封装。

既然上面那种方式不能再次进行封装,那我们不妨换一种思路:

既然实现起来有bug,我们不用它不就行了?

来,一起试试Gson将json字符串转java对象有没有问题:

Number number = new Number((byte)1, (short)2, 3, 4L, 5D, 6F);
String gsonStr = new Gson().toJson(number);
System.out.println(gsonStr);

Number numberGson = new Gson().fromJson(gsonStr, Number.class);
System.out.println(numberGson.toString());

 

我们可以看到,json字符串转java对象,通过gson转换,也是没有问题的。

那么,我们就可以:将json数组字符串先转json数组,再对其进行遍历将其(json对象)转成java对象,塞到list当中。

/*
 * JsonArray字符串转List(Gson)
 * @description:
 * @date: 2022/3/24 19:21
 * @param: jsons json数组字符串
 * @param: clazz 实体类
 * @return: java.util.List<T>
 */
@Nullable
public static <T> List<T> toJavaBeansByGson(String jsons, Class<T> clazz) {
    // net.sf.json
    JSONArray jsonArray = JSONArray.fromObject(jsons);

    if (arraysIsEmpty(jsonArray)) return null;
    
    List<T> beans = new ArrayList<>(jsonArray.size());
    jsonArray.forEach(netJson -> beans.add(new Gson().fromJson(netJson.toString(), clazz)));
    return beans;
}

测试

Number number = new Number((byte)1, (short)2, 3, 4L, 5D, 6F);
List<Number> numbers = new ArrayList<>(1);
numbers.add(number);
String gsonStrs = new Gson().toJson(numbers);
System.out.println(gsonStrs);

List<Number> numberList = JsonUtils.toJavaBeansByGson(gsonStrs, Number.class);
System.out.println(numberList);

 

我们可以看到,数值类型的转换是没有问题的。

总结:

当我们少量需要使用gson将字符串转list时,可以使用第一种方式;

如果有大量位置需要用gson完成转换的话,可以考虑使用第二种实现方式。

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

posted @ 2022-03-25 12:01  Marydon  阅读(2232)  评论(0编辑  收藏  举报