Jackson的多态序列化与反序列化

背景

最近同事在使用Jackson做列表元素多态的反序列化时,遇到个有意思的问题,这里来记录下,以便后面使用时方便查找。具体场景,我们且来看下面代码:

@Data    static class Animal {        private String name;    }
    @Data    static class Dog extends Animal {        private int age;    }
    @Data    static class Cat extends Animal {        private boolean isCute;    }
    @Data    static class ViewDO{        private List<Animal> animals;    }
 public static void main(String[] args) throws IOException {
        // 1.构建view对象        ViewDO viewDO = new ViewDO();        List<Animal> 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.序列化ViewDO        ObjectMapper 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(objectMapper.writeValueAsString(viewDO));}

运行上面代码,步骤4输出为:

{"animals":[{"name":"Buddy","age":3},{"name":"Whiskers","cute":true}]}

步骤5输出为:

{"animals":[{"name":"Buddy"},{"name":"Whiskers"}]}

根据步骤5我们可以知道反序列化后只保留了父类Animal的name属性,其子类Dog和Cat的独有属性被丢掉了。

解决

其原因也容易理解,就是因为反序列化时ViewDO中的animals的列表元素类型为Animal,jackson并不感知其子类Dog和Cat的存在。要解决这个问题,需要再序列化时把元素的类型信息保存到序列化结果中,这样反序列化时,就知道当前元素使用那个子类进行反序列化。

为实现上面效果,我们只需要对ViewDO 类改造如下:

@Data    static class ViewDO{        @JsonTypeInfo(                use = JsonTypeInfo.Id.NAME, // 使用类名作为类型标识                include = JsonTypeInfo.As.PROPERTY, // 将类型信息作为 JSON 属性                property = "@class" // 类型信息的字段名为 "@class"        )        @JsonSubTypes({                @JsonSubTypes.Type(value = Dog.class, name = "dog"), // 子类 Dog                @JsonSubTypes.Type(value = Cat.class, name = "cat")}        )        private List<Animal> animals;    }

如上我们添加了 @JsonTypeInfo和@JsonSubTypes注解,添加后,会在序列化时,在序列化结果内添加一个@class属性,属性的值为dog或者cat。加上注解后,步骤4序列化的结果为:

{"animals":[{"@class":"dog","name":"Buddy","age":3},{"@class":"cat","name":"Whiskers","cute":true}]}

步骤5反序列化结构为:

{"animals":[{"@class":"dog","name":"Buddy","age":3},{"@class":"cat","name":"Whiskers","cute":true}]}

可知反序列化时可感知子类了,可根据@class信息正确使用子类进行反序列化。

戳下面阅读

👇

我的第三本书    我的第二本书    我的第一本书

程序员的办公神器    ForkJoinPool    K8s网络模型

点亮再看哦👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值