Jackson容许配置多态类型处理,当进行反序列话时,Json数据匹配的对象可能有多个子类型,为了正确的读取对象的类型,咱们须要添加一些类型信息。java
@JsonTypeInfo
@JsonTypeInfo
这个注解能够直接放在类上,也能够放在某个属性上:下面是内部的属性值git
use: (必选):定义使用哪种类型识别码(property为识别码的key),可选值有多种:在序列化时标志出不一样的类型用什么区分,用在反序列化时转换成响应的类型github
use属性值 | 若不指定property则默认 | 做用 | 是否依赖JsonTypeInfo的值 |
---|---|---|---|
JsonTypeInfo.Id.NAME | @type | 使用JsonTypeInfo的值做为识别码的值 | 若是有多个子类的状况,必须有 @JsonSubTypes,不然没法判断是哪一个子类 |
JsonTypeInfo.Id.CLASS | @class | 用类的全路劲名称来做为识别码的值 | 与是否有@JsonSubTypes无关 |
JsonTypeInfo.Id.MINIMAL_CLASS | @c | 表示具备最小路径的Java类名称用做识别 | 是否有@JsonSubTypes无关 |
JsonTypeInfo.Id.NONE | 暂不介绍 | ||
JsonTypeInfo.Id.CUSTOM | 暂不介绍 |
设置识别码包含在哪里。 包含类型元数据的一种机制web
include属性值 | 做用 | ||
---|---|---|---|
JsonTypeInfo.As.PROPERTY | 做为POJO的属性出现 | 默认 | |
JsonTypeInfo.As.WRAPPER_OBJECT | 做为一个包装的对象 | ||
JsonTypeInfo.As.WRAPPER_ARRAY | 做为一个包装的数组 | ||
JsonTypeInfo.As.EXTERNAL_PROPERTY | 做为一个额外的属性,跟POJO同级,只能用于属性,如何做用于类则跟JsonTypeInfo.As.PROPERTY是相同效果 | ||
JsonTypeInfo.As.EXISTING_PROPERTY | 序列化,则Jackson不主动处理,由咱们自行处理。 反序列化的时候,跟JsonTypeInfo.As.PROPERTY的处理相同; |
设置识别码是名称, 自定义的区分类型的id,根据 use的属性值不一样,默认值不一样,具体默认值看(1.1.1)json
visible(可选):定义识别码在反序列化时是否保留(无论false或true都不影响序列化)。默认是false,表示Jackson能够将识别码识别为类型后就删除。数组
@JsonSubTypes
能够用来代表这个父类的子类型有哪些微信
public abstract class Human { private String district; @Data public static class Man extends Human { private String manField; } @Data public static class Woman extends Human { private String womanField; } }
@Test public void normal() throws IOException { ObjectMapper mapper = new ObjectMapper(); Man man = new Man(); man.setManField("男人"); man.setDistrict("山西"); String json = mapper.writeValueAsString(man); System.out.println(json); // {"district":"山西","manField":"男人"} //报错 子类转父类,再不能直接序列化为子类 man =((Man)mapper.readValue(json, Human.class)) ; }
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) public abstract class Human { private String district; @Data public static class Man extends Human { private String manField; } @Data public static class Woman extends Human { private String womanField; } }
@Test public void testOne() throws IOException { ObjectMapper mapper = new ObjectMapper(); Man man = new Man(); man.setManField("男人"); man.setDistrict("北京"); String manJson = mapper.writeValueAsString(man); log.info("序列化Man :【 {} 】", manJson); Human human = mapper.readValue(manJson, Human.class); log.info("子类转父类 ======================"); String humanJson = mapper.writeValueAsString(human); log.info("反序列化man -> Human :【 {} 】", humanJson); log.info("human.getDistrict() :【 {} 】", human.getDistrict()); }
使用JsonTypeInfo的值做为识别码的值,若是有多个子类的状况,必须有 @JsonSubTypes,不然没法判断是哪一个子类app
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"@type":"man","district":"北京","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"@type":"man","district":"北京","manField":"男人"} 】 human.getDistrict() :【 北京 】
**use = JsonTypeInfo.Id.NAME
, 若是不写property
,则识别码 的名字默认为 @type
**svg
根据Json数据,识别以后,其值为@JsonSubTypes.Type(value = Human.Man.class, name = "man")
中子类Man的name值测试
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"type":"man","district":"北京","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"type":"man","district":"北京","manField":"男人"} 】 human.getDistrict() :【 北京 】
**用类的全路劲名称来做为识别码的值,和@JsonSubType不要紧,写上了也不起做用,能够自动判断有哪些子类 **
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"type":"com.healerjean.proj.a_test.json.jackson.d02_JsonType.Human$Man","district":"北京","manField":"男人"} 】 反序列化man -> Human :【 {"type":"com.healerjean.proj.a_test.json.jackson.d02_JsonType.Human$Man","district":"北京","manField":"男人"} 】 human.getDistrict() :【 北京 】
**use = JsonTypeInfo.Id.CLASS
, 若是不写property
,则识别码 的名字默认为 @class
**
根据Json数据,识别以后,值为,这个子类所在类路径,用.链接
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 序列化Man :【 {"@class` ":"com.healerjean.proj.a_test.json.jackson.d02_JsonType.Human$Man","district":"北京","manField":"男人"} 】 反序列化man -> Human :【 {"@class` ":"com.healerjean.proj.a_test.json.jackson.d02_JsonType.Human$Man","district":"北京","manField":"男人"} 】 human.getDistrict() :【 北京 】
**表示具备最小路径的Java类名称用做识别码的值,和@JsonSubType不要紧,写上了也不起做用,能够自动判断有哪些子类 **
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) 序列化Man :【 {"@c":".Human$Man","district":"北京","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"@c":".Human$Man","district":"北京","manField":"男人"} 】human.getDistrict() :【 北京 】
use = JsonTypeInfo.Id.CLASS
, 若是不写property
,则识别码 的名字默认为 @c
**默认是 JsonTypeInfo.As.PROPERTY,上面全部的都是以它进行测试的
做为一个包装的对象
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"man":{"district":"北京","manField":"男人"}} 】 子类转父类 ====================== 反序列化man -> Human :【 {"man":{"district":"北京","manField":"男人"}} 】 human.getDistrict() :【 北京 】
做为一个包装的数组 (看下面,这个数组但是不太规则哦,就是说里面放的不必定的同类型的),和有无property无关,看下面的测试打印结果就知道
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 ["man",{"district":"北京","manField":"男人"}] 】 子类转父类 ====================== 反序列化man -> Human :【 ["man",{"district":"北京","manField":"男人"}] 】 human.getDistrict() :【 北京 】
做为一个额外的属性,跟POJO同级,只能用于属性,如何做用于类则跟JsonTypeInfo.As.PROPERTY是相同效果
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"type":"man","district":"北京","manField":"男人"} 】 类转父类 ====================== 反序列化man -> Human :【 {"type":"man","district":"北京","manField":"男人"} 】 human.getDistrict() :【 北京 】
反序列化 :
序列化 :
序列化的时候,跟它没半毛钱关系,可是不会像上面的那样
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) public class Human { private String district; private String type; @Data public static class Man extends Human { private String manField; } @Data public static class Woman extends Human { private String womanField; } } 序列化Man :【 {"district":"北京","type":"man","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"district":"北京","type":null,"manField":"男人"} 】 human.getDistrict() :【 北京 】
设置识别码是名称,根据use的属性,通常状况下有默认值
除了JsonTypeInfo.As.EXISTING_PROPERTY 有些特殊以外,JsonTypeInfo.As.EXTERNAL_PROPERTY、JsonTypeInfo.As.PROPERTY 注解的类中有了相同的属性(剩下的不讲解,由于其余的和property 没半毛钱关系),则会出现两次 以JsonTypeInfo.As.PROPERTY 举例
注意点
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) public class Human { private String district; private String type; @Data public static class Man extends Human { private String manField; } @Data public static class Woman extends Human { private String womanField; } } @Test public void testOne() throws IOException { ObjectMapper mapper = new ObjectMapper(); Man man = new Man(); man.setManField("男人"); man.setDistrict("北京"); man.setType("lalala"); String manJson = mapper.writeValueAsString(man); log.info("序列化Man :【 {} 】", manJson); Human human = mapper.readValue(manJson, Human.class); log.info("子类转父类 ======================"); String humanJson = mapper.writeValueAsString(human); log.info("反序列化man -> Human :【 {} 】", humanJson); log.info("human.getDistrict() :【 {} 】", human.getDistrict()); log.info("human.getType() :【 {} 】", human.getType()); } 序列化Man :【 {"type":"man","district":"北京","type":"lalala","manField":"男人"} 子类转父类 ====================== 反序列化man -> Human :【 {"type":"man","district":"北京","type":"lalala","manField":"男人"} 】 human.getDistrict() :【 北京 】 human.getType() :【 lalala 】
visible(可选):定义识别码在反序列化
(反序列为对象内部是否保留给字段)时是否保留(无论false或true都不影响序列化)。默认是false,表示Jackson能够将识别码识别为类型后就删除。
@Test public void testOne() throws IOException { ObjectMapper mapper = new ObjectMapper(); Man man = new Man(); man.setManField("男人"); man.setDistrict("北京"); man.setType("1"); String manJson = mapper.writeValueAsString(man); log.info("序列化Man :【 {} 】", manJson); //只剩下一个type,必须放在第一个,这样才能识别子类 manJson = "{\"type\":\"man\",\"district\":\"北京\",\"manField\":\"男人\"} "; Human human = mapper.readValue(manJson, Human.class); log.info("子类转父类 ======================"); String humanJson = mapper.writeValueAsString(human); log.info("反序列化man -> Human :【 {} 】", humanJson); log.info("human.getDistrict() :【 {} 】", human.getDistrict()); log.info("human.getType() :【 {} 】", human.getType()); }
@Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = false ) @JsonSubTypes({ @JsonSubTypes.Type(value = Human.Man.class, name = "man"), @JsonSubTypes.Type(value = Human.Woman.class, name = "woman"), }) 序列化Man :【 {"type":"man","district":"北京","type":"1","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"type":"man","district":"北京","type":null,"manField":"男人"} 】 human.getDistrict() :【 北京 】 human.getType() :【 null 】
反序列化会把它当作一个属性值处理(保留给字段了),也就是说反序列化后仍是可见的,若是在这个上面我测试的Json中再加一个type,那么这个这个识别码照样能打印,可是会失效
序列化Man :【 {"type":"man","district":"北京","type":"1","manField":"男人"} 】 子类转父类 ====================== 反序列化man -> Human :【 {"type":"man","district":"北京","type":"man","manField":"男人"} 】 human.getDistrict() :【 北京 】 human.getType() :【 man 】 若是在这个上面我测试的Json中再加一个type,那么这个这个识别码照样能打印,可是会失效 manJson = "{\"type\":\"man\",\"district\":\"北京\",\"type\":\"1\",\"manField\":\"男人\"} "; 打印结果 反序列化man -> Human :【 {"type":"man","district":"北京","type":"1","manField":"男人"} 】 human.getType() :【 1 】感兴趣的,欢迎添加博主微信
哈,博主很乐意和各路好友交流,若是满意,请打赏博主任意金额,感兴趣的在微信转帐的时候,备注您的微信或者其余联系方式。添加博主微信哦。
请下方留言吧。可与博主自由讨论哦
微信 | 微信公众号 | 支付宝 |
---|---|---|
![]() |
![]() |
![]() |