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完成轉換的話,可以考慮使用第二種實現方式。