@JsonTypeInfo
在java里面由于有多态的用法,所以在涉及到多态的序列化和反序列化的时候,需要指定一些子类的相关信息告诉Jackson,这样Jackson在序列化和反序列的时候才不出错,我们先举个例子,如下
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
@Getter
@Setter
class View{
private List<Sharp> sharps;
}
abstract class Sharp{
}
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
class Circle extends Sharp{
@Getter
@Setter
private String radius;
}
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
class Rectangle extends Sharp{
@Getter
@Setter
private String length;
@Getter
@Setter
private String width;
}
测试代码如下
@Test
public void JsonTypeInfoTest() throws Exception{
CombineJacksonAnnotation.Circle circle = CombineJacksonAnnotation.Circle.of("12");
CombineJacksonAnnotation.Rectangle rectangle = CombineJacksonAnnotation.Rectangle.of("12","13");
CombineJacksonAnnotation.View view = CombineJacksonAnnotation.View.of(Lists.newArrayList(circle,rectangle));
System.out.println(om.writeValueAsString(view));
}
结果如下
{
"sharps" : [ {
"radius" : "12"
}, {
"length" : "12",
"width" : "13"
} ]
}
看上面的序列化结果貌似没有什么问题,但是如果我们直接的使用这个Json串继续做反序列化,看看会发生什么
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Sharp` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{
"sharps" : [ {
"name" : "circleType",
"radius" : "12"
}, {
"name" : "rectangleType",
"length" : "12",
"width" : "13"
} ]
}"; line: 2, column: 16] (through reference chain: com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$View["sharps"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
究其原因,是因为在反序列化的时候,我们没有告诉Jackson其多态信息,Jackson在反序列化的时候,就直接的按照常规的方式去反序列化成Sharp,由于Sharp是个抽象对象,实例化的时候肯定会出错的,即使Sharp不是抽象类,属性也会匹配不上而报错。
Jackson提供了@JsonTypeInfo来处理多态的序列化和反序列化,如下,我们在Sharp打上如下的标签
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "name")
序列化结果如下
{
"sharps" : [ {
"name" : "CombineJacksonAnnotation$Circle",
"radius" : "12"
}, {
"name" : "CombineJacksonAnnotation$Rectangle",
"length" : "12",
"width" : "13"
} ]
}
可以看到在加上@JsonTypeInfo注解之后,在序列化的时候,会将类的信息也序列化到Json串里面。
现在简单的介绍下@JsonTypeInfo里面几个属性的作用
1 use 非空就是子类在序列化的手,使用什么样式序列化到Json串里面去,可选值如下
NONE 与不写一样
CLASS 使用类的全限定名作为value,默认使用@class作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下
"@class" : "com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Circle",
MINIMAL_CLASS 使用最小类型作为value,默认使用@c作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下
"@c" : ".CombineJacksonAnnotation$Circle",
@NAME 使用类名作为value,默认使用@type作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下
"@type" : "CombineJacksonAnnotation$Circle",
@CUSTOM 自定义
2include 默认是
PROPERTY 就是说序列化后的类型信息会默认作为pojo的属性输出
WRAPPER_OBJECT 使用包装类型输出,如下
"CombineJacksonAnnotation$Circle" : {
"radius" : "12"
}
WRAPPER_ARRAY 使用包装数组输出,如下
[ "CombineJacksonAnnotation$Circle", {
"radius" : "12"
} ]
EXTERNAL_PROPERTY与EXISTING_PROPERTY较相识,不介绍
但是我们再反序列化的时候还是会报错,如下
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'CombineJacksonAnnotation$Circle' as a subtype of [simple type, class com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Sharp]: known type ids = [] (for POJO property 'sharps')
at [Source: (String)"{
"sharps" : [ {
"name" : "CombineJacksonAnnotation$Circle",
"radius" : "12"
}, {
"name" : "CombineJacksonAnnotation$Rectangle",
"length" : "12",
"width" : "13"
} ]
}"; line: 3, column: 14] (through reference chain: com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$View["sharps"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
这个是因为我们没有将子类与序列化之后的类型信息关联起来,我们在Sharp上面添加下面的注解@JsonSubTypes
@JsonSubTypes(value = {@JsonSubTypes.Type(value =Circle.class),@JsonSubTypes.Type(value =Rectangle.class)})
这个注解意思是,Sharp包含多少个subType,然后在Circle上面再打上注解如下
@JsonTypeName("circleType")
在Rectangle打上注解如下
@JsonTypeName("rectangleType")
序列化之后的结果如下
{
"sharps" : [ {
"name" : "circleType",
"radius" : "12"
}, {
"name" : "rectangleType",
"length" : "12",
"width" : "13"
} ]
}
反序列化也成功了,该注解主要用于多态的场景,在关键时候是解决问题的利器。
网友评论