Gson 如何反序列化多态对象列表

最近,我们遇到了一种情况,我从 REST 端点接收到 JSON 格式的对象列表。 到目前为止,这没有什么不寻常的,也不是问题。 然而,问题是对象是多态的,需要解析子类特定的字段。 以前的解决方案是手动解析它。 对我们来说,这是不可接受的,我正在寻找更好的解决方案。 因为我们已经在使用 Gson,所以我希望有一个技巧可以让它与 Gson 一起工作。 不幸的是,大多数人建议编写一个自定义的反序列化器,这仍然比手动编写要好,但代码也很多。 最后,我找到了 RuntimeTypeAdapterFactory 类,它很好地解决了这个问题。

让我们假设项目使用以下类:

public class Animal {  
    private String name;
        private String type; // 这指定了它是哪种动物
    }

    public class Dog extends Animal {
        private boolean playsCatch;
    }

    public class Cat extends Animal {
        private boolean chasesRedLaserDot;
    }
}

想象一下,我们会得到一个 Animal-Objects 列表,其中包含随机的子类。 有几只狗,有几只猫,没有特别的顺序。

如何解决

正如介绍中提到的,RuntimeTypeAdapterFactory 类就是解决方案。 它不附带 Gson 包,因此我们必须下载并将其手动添加到项目中。

接下来,我们设置映射。

String responseJson = new String(responseBody); // 从服务端获取的数据

// 哪种格式有服务器的响应
final TypeToken<ServiceResponse> requestListTypeToken = new TypeToken<ServiceResponse>() {};

// 添加所有不同的容器类及其标志
final RuntimeTypeAdapterFactory<AbstractContainer> typeFactory = RuntimeTypeAdapterFactory  
        .of(Animal.class, "type") // 在指定哪个是父类以及哪个字段具体化子类时。
        .registerSubtype(Dog.class, "dog") // 如果标志等于类名,则可以跳过第二个参数。 只有在“类型”字段不等于类名时才需要这样做。
        .registerSubtype(Cat.class, "cat");

final Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeFactory).create();

// 映射
final ServiceResponse deserializedRequestList = gson.fromJson(responseJson, requestListTypeToken.getType() );  

请注意,如果服务返回了意料之外的类型,例如 Horse,Gson 会崩溃! 尽管如此,这应该为我们提供一个多态对象列表的自动映射,只需要很少的代码行。