Gson反序列化List<T>数据返回问题解决方案

先来看一下Gson官方的阐述

Serializing and Deserializing Generic Types

When you call toJson(obj), Gson calls obj.getClass() to get information on the fields to serialize. Similarly, you can typically pass MyClass.class object in the fromJson(json, MyClass.class) method. This works fine if the object is a non-generic type. However, if the object is of a generic type, then the Generic type information is lost because of Java Type Erasure. Here is an example illustrating the point:

class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

大致意思就是:如果使用 new Gson().fromJson(json, Class<T>) 来反序列化会出现问题,导致JSON字符串无法反序列化为指定的泛型Bean。

究其原因就一个:Java代码编译后会擦除泛型,从而导致反序列化时,程序不清楚需要反序列化为什么类型的对象实例。

官方也给出了解决方案

The above code fails to interpret value as type Bar because Gson invokes foo.getClass() to get its class information, but this method returns a raw class, Foo.class. This means that Gson has no way of knowing that this is an object of type Foo<Bar>, and not just plain Foo.

You can solve this problem by specifying the correct parameterized type for your generic type. You can do this by using the TypeToken class.

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);

gson.fromJson(json, fooType);

The idiom used to get fooType actually defines an anonymous local inner class containing a method getType() that returns the fully parameterized type.

翻译一下大意:可以通过为泛型类型指定正确的参数化类型来解决此问题。您可以通过使用TypeToken类来实现这一点。

借助 TypeToken 这个类对象来弥补这一缺点。

本人所使用的的Gson版本是V2.9.0

官方教程有提到,使用示例:

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();

其中:Foo<Bar>是指定的具体泛型类型。这样在反序列化时,不是直接放入泛型class:

gson.fromJson(json, clazz)

而是使用得到的Type类型传入

gson.fromJson(json, type)
type -> 为TypeToken后的Type类型

但教程点滞后,因为TypeToken 的构造方法均为protected,且为抽象类。官方提供的了已静态TypeToken.of(clazz) 方法,其内部有一个实现了该类的内部类SimpleTypeToken。

完整的使用示例:

// 以Foo class为例
Type type = TypeToken(Foo.class).getType();
Foo bean = new Gson().from(jsonStr, type);

接下来是针对List<T>的这种反序列化。在Java语法中,如果使用上述方式,语法上都校验不过,耿别谈反序列化了。

需要借助Gson内部的一些对象来实现。具体代码如下:

public static <T> List<T> fromJson(String json, Class<T> entityClazz) {
    Gson gson = new Gson();
    // 将数据先转为JsonArray
    JsonArray list = gson.fromJson(json, JsonArray.class);
    // 遍历再将每一个JsonElement反序列化为指定的Type,装进集合后返回
    List<T> data = new LinkedList<>();
    Type type = TypeToken.of(entityClazz).getType();
    for (JsonElement object : list) {
        data.add(gson.fromJson(object, type));
    }
    return data;
}

当然还有很多,这只是目前棘手的一点。有兴趣可自行研究,GitHub官网:https://github.com/google/gson/blob/master/UserGuide.md

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流沙QS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值