摘要:@Datastatic class Animal {private String name;}@Datastatic class Dog extends Animal {private int age;}@Datastatic class Cat extend
最近同事在使用Jackson做列表元素多态的反序列化时,遇到个有意思的问题,这里来记录下,以便后面使用时方便查找。具体场景,我们且来看下面代码:
@Datastatic class Animal {private String name;}@Datastatic class Dog extends Animal {private int age;}@Datastatic class Cat extends Animal {private boolean isCute;}@Datastatic class ViewDO{private List animals;}public static void main(String args) throws IOException {// 1.构建view对象ViewDO viewDO = new ViewDO;List animals = new ArrayList;viewDO.animals = animals;// 2.添加Dog实例Dog dog = new Dog;dog.setName("Buddy");dog.setAge( 3);animals.add(dog);// 3.添加Cat实例Cat cat = new Cat;cat.setName( "Whiskers");cat.setCute(true);animals.add(cat);// 4.序列化ViewDOObjectMapper objectMapper = new ObjectMapper;objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);String JSON = objectMapper.writeValueAsString(viewDO);System.out.println(json);// 5.反序列化viewDO = objectMapper.readValue(json, ViewDO.class);System.out.println(view}运行上面代码,步骤4输出为:
{"animals":[{"name":"Buddy","age":3},{"name":"Whiskers","cute":true}]}步骤5输出为:
ViewDO(animals=[.Animal(name=Buddy), .Animal(name=Whiskers)])根据步骤5我们可以知道反序列化后只保留了父类Animal的name属性,其子类Dog和Cat的独有属性被丢掉了。
其原因也容易理解,就是因为反序列化时ViewDO中的animals的列表元素类型为Animal,jackson并不感知其子类Dog和Cat的存在。要解决这个问题,需要再序列化时把元素的类型信息保存到序列化结果中,这样反序列化时,就知道当前元素使用那个子类进行反序列化。
为实现上面效果,我们只需要对ViewDO 类改造如下:
@Datastatic class ViewDO{@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, // 使用类名作为类型标识include = JsonTypeInfo.As.PROPERTY, // 将类型信息作为 JSON 属性property = "@class" // 类型信息的字段名为 "type")@JsonSubTypes({@JsonSubTypes.Type(value = Dog.class, name = "dog"), // 子类 Dog@JsonSubTypes.Type(value = Cat.class, name = "cat")})private List animals;}{"animals":[{"@class":"dog","name":"Buddy","age":3},{"@class":"cat","name":"Whiskers","cute":true}]}步骤5反序列化结构为:
.ViewDO(animals=[.Dog(age=3), .Cat(isCute=true)])可知反序列化时可感知子类了,可根据@class信息正确使用子类进行序列化。
来源:科技凡人说
免责声明:本站系转载,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与本站联系,我们将在第一时间删除内容!