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 】感興趣的,歡迎添加博主微信
哈,博主很樂意和各路好友交流,若是滿意,請打賞博主任意金額,感興趣的在微信轉帳的時候,備註您的微信或者其餘聯繫方式。添加博主微信哦。
請下方留言吧。可與博主自由討論哦
微信 | 微信公衆號 | 支付寶 |
---|---|---|
![]() |
![]() |
![]() |