• 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 value;
    }
    Gson gson = new Gson();
    Foo foo = new Foo();
    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) 来反序列化会出现问题,导致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, 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>() {}.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>() {}.getType();

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

    gson.fromJson(json, clazz)

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

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

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

    完整的使用示例:

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

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

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

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

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

  • 相关阅读:
    干货分享 | 一文了解TSMaster中Seed&key的两种处理方法
    2D游戏案例:游戏场景搭建
    CSAPP第4章:RISC和CISC指令集
    UNet网络
    组件化与插件化
    Linux内核分析(十六)--内存管理之管理机制
    安装TPDSS
    《DevOps 精要:业务视角》- 读书笔记(三)
    redisson分布式限流[RRateLimiter]源码分析
    从零开始自己动手写阻塞队列
  • 原文地址:https://blog.csdn.net/gengzhy/article/details/126799295