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完成转换的话,可以考虑使用第二种实现方式。
本文来自博客园,作者:Marydon,转载请注明原文链接:https://www.cnblogs.com/Marydon20170307/p/16054020.html