1. 程式人生 > 其它 >gson 反序列化,整數變小數的終極解決方案

gson 反序列化,整數變小數的終極解決方案

1.情景展示

使用gson進行反序列化(json轉java物件)的時候,你可能會遇到明明key對應的值是整數,而進行反序列化後,卻變成了小數(後面加上了.0)。

如何解決這個問題?

2.具體分析

準備工作

檢視程式碼
/**
 * 數值型別實體類
 * @description: 包含整數和小數
 * @author: Marydon
 * @date: 2022-03-24 18:48
 * @version: 1.0
 * @email: [email protected]
 */
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完成轉換的話,可以考慮使用第二種實現方式。

寫在最後

  哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!

 相關推薦: