首页 > 解决方案 > 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}]

我究竟做错了什么?

标签: javagson

解决方案


您的代码有多个问题:

  • 结果列表类型是原始的,因此在编译时它不是类型安全的。
  • 如果可能,首选接口,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

推荐阅读