【问题标题】:Gson JsonArray to List long type becomes scientific notationGson JsonArray to List long 类型变成科学记数法
【发布时间】:2021-03-12 03:30:23
【问题描述】:

当我尝试将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}]

我做错了什么?

【问题讨论】:

  • 由于您的帖子不完整,请发布一个可重现的最小示例:1)实际的 JSON 数组对象或构造它的文档是什么? 2)您要转换的列表的实际元素类别是什么?
  • 哦,我没有将 JSON 视为独立部分,但只是在“接收”调试输出中注意到它。无论如何,您的帖子越清晰,阅读它的人就会越好,并且可能对您有所帮助。

标签: java gson


【解决方案1】:

您的代码存在多个问题:

  • 结果列表类型是原始的,因此在编译时它不是类型安全的。
  • 如果可能,首选接口List,而不是类ArrayList
  • T 的类型参数未绑定到它返回的列表,因此如果有的话几乎没有意义。
  • 从 type 参数创建类型标记的方式不起作用:在运行时它仍然映射到 java.lang.Object 并且 Gson 试图选择 它认为最好的一个。
  • 不应(而且不能)在此类方法中创建类型标记,而是从调用站点传递。此外,它们是不可变的,因此也是线程安全的。
  • 您无需在每次调用此方法时都创建Gson 实例。
  • 在这种情况下将 JSON 树转换为字符串是非常没用的,因为 Gson 可以遍历 JSON 树并读取 JSON 令牌流,而无需花费双倍的时间 解析。

当我要求你提供列表元素类时,我试图暗示你的实际代码是这样的:

ArrayList arrayList = toArrayList(jsonArray);
System.out.println(arrayList);

无法工作。请注意以下几点:

  • 此代码(也可能是您的代码)根本没有提及元素类型。
  • 如果您检查 real 列表元素类,您会看到它被反序列化为 com.google.gson.internal.LinkedTreeMap--来自 Gson 的泛型类型 我在上面谈论的观点 (arrayList.get(0).getClass())。
  • JSON 不区分“long”、“integer”、“short”、“u64”、“i8”等。 JSON 数字类型只是一个数字。格森 选择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

【讨论】:

  • 我没有办法创建对象进行转换,因为我的JsonArray中的元素是不确定的,我只需要将JsonArray转换成List,方便遍历操作。
  • 如果JsonArray(以及所有JsonElement子类)可以表示不确定的JSON结构,为什么还要转换JSON数组?
猜你喜欢
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
相关资源
最近更新 更多