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完成轉換的話,可以考慮使用第二種實現方式。
寫在最後
哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!