java - Gson JsonArray to List long 类型变成科学记数法
问题描述
当我尝试将 JsonArray 转换为 List 时,我得到一个 long 类型转换错误,代码如下
public static <T> ArrayList toArrayList(JsonArray jsonArray) {
System.out.println("---=Receive====>>"+jsonArray);
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.setLongSerializationPolicy(LongSerializationPolicy.STRING).create();
return gson.fromJson(jsonArray.toString(),
new TypeToken<List<T>>() {}.getType());
}
结果:
--=Receive====>>[{"serialNo":"1339497989051277312","createBy":"xxxx","createDate":1608196182000,"updateBy":"xxxx","updateDate":1615444156000}]
-=result--->>[{serialNo=1339497989051277312, createBy=xxxx, createDate=1.608196182E12, updateBy=xxxx, updateDate=1.615444156E12}]
我究竟做错了什么?
解决方案
您的代码有多个问题:
- 结果列表类型是原始的,因此在编译时它不是类型安全的。
- 如果可能,首选接口,
List
而不是类。ArrayList
- 的类型参数
T
未绑定到它返回的列表,因此如果有的话几乎没有意义。 - 您从类型参数创建类型标记的方式不起作用:在运行时它仍然被映射到
java.lang.Object
并且 Gson 试图选择它认为最好的一个。 - 类型标记不应该(而且不能)在这样的方法中创建,而是从调用站点传递。此外,它们是不可变的,因此也是线程安全的。
- 您无需在
Gson
每次调用此方法时都创建实例。 - 在这种情况下,将 JSON 树转换为字符串是非常没用的,因为 Gson 可以遍历 JSON 树并读取 JSON 令牌流,而无需花费双倍的时间进行解析。
当我要求您提供列表元素类时,我试图暗示您的实际代码如下所示:
ArrayList arrayList = toArrayList(jsonArray);
System.out.println(arrayList);
不能工作。请注意以下事项:
- 这段代码(也可能是你的)根本没有提及元素类型。
- 如果您检查真正的列表元素类,您会看到它被反序列化为
com.google.gson.internal.LinkedTreeMap
-- 从 Gson 角度来看的泛型类型(我在上面谈到arrayList.get(0).getClass()
)。 - JSON 不区分“long”、“integer”、“short”、“u64”、“i8”等。JSON 数字类型只是一个数字。Gson 选择
java.lang.Double
这种类型可以满足大多数实际需求(BigDecimal
将是一个更好的选择,但它也很消耗内存;这也是setLongSerializationPolicy
忽略提示的原因)。
Gson 尽其所能为您做到了,它做到了。
总结一下,你必须做的是:
private static final Gson gson=new GsonBuilder()
.disableInnerClassSerialization()
.disableHtmlEscaping()
.create();
public static<E> List<E> toArrayList(final JsonArray jsonArray,final TypeToken<?extends List<? extends E>> typeToken){
return gson.fromJson(jsonArray,typeToken.getType());
}
final class MyObject {
@Expose
@SerializedName("serialNo")
final String serialNo;
@Expose
@SerializedName("createBy")
final String createBy;
@Expose
@SerializedName("createDate")
final long createDate;
@Expose
@SerializedName("updateBy")
final String updateBy;
@Expose
@SerializedName("updateDate")
final long updateDate;
private MyObject(final String serialNo, final String createBy, final long createDate, final String updateBy, final long updateDate) {
this.serialNo = serialNo;
this.createBy = createBy;
this.createDate = createDate;
this.updateBy = updateBy;
this.updateDate = updateDate;
}
}
private static final TypeToken<List<MyObject>> listOfMyObjectTypeToken = new TypeToken<List<MyObject>>() {};
// ...
final List<MyObject> myObjects = toArrayList(jsonArray, listOfMyObjectTypeToken);
System.out.println(myObjects);
System.out.println(myObjects.get(0).getClass().getSimpleName());
传递类型标记为 Gson 提供了足够的信息来处理要处理的类型。原因如下:
[MyObject(serialNo=1339497989051277312, createBy=xxxx, createDate=1608196182000, updateBy=xxxx, updateDate=1615444156000)]
MyObject
推荐阅读
- python - Robot Pepper / 获取障碍物检测值
- xml - XPath 从 SSRS 的 XML 数据源中的 RSS 提要中提取项目
- python - Python win32com.client - 只有在我打开 Outlook 时才会发出电子邮件
- python - 如何改进此 Python 脚本以替换 dbf 文件中的记录?
- tfs - TFS 代码审查 - 你可以在本地运行某人的变更集以测试它是否有效?
- python-3.x - 如何为 python3 安装 pyobjc?
- python - 具有原始规范 Python 的模拟类
- ios - 如何从 SceneKit 的坐标绘制 2D UIView?
- sql - 如何查询 DNN (DotNetNuke) 数据库以查找最近修改过的页面
- scala - 使用 mapWithState Spark Streaming 过滤部分重复项