Java中Jackson的多態(tài)反序列化詳解
Jackson多態(tài)反序列化
多態(tài)序列化與反序列化,主要是借助于Jackson的@JsonTypeInfo與@JsonSubTypes注解實(shí)現(xiàn),下面將通過(guò)幾個(gè)例子來(lái)簡(jiǎn)述其運(yùn)用。
首先,創(chuàng)建幾個(gè)基本的實(shí)體類(lèi)。這些類(lèi)都比較簡(jiǎn)單,有共同的屬性也有不同的屬性,這里為了簡(jiǎn)單,共同屬性就只有一個(gè)type。
@Data public class Person { protected Integer type; }
@EqualsAndHashCode(callSuper = true) @Data public class Student extends Person { private String studentName; }
@EqualsAndHashCode(callSuper = true) @Data public class Teacher extends Person { private String teacherName; }
@EqualsAndHashCode(callSuper = true) @Data public class Doctor extends Person{ private String doctorName; }
1、通過(guò)類(lèi)型判斷
在父類(lèi)上加如下注解。因?yàn)槭峭ㄟ^(guò)類(lèi)型進(jìn)行序列化,所以只需要加一個(gè)注解就夠了。
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) @Data public class Person { protected Integer type; }
測(cè)試
@Test void test1() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Student student = new Student(); student.setType(0); student.setStudentName("三好學(xué)生~"); System.out.println(objectMapper.writeValueAsString(student)); String json1 = "{\"@class\":\"com.example.jackson.Student\",\"studentName\":\"三好學(xué)生~\",\"type\":null}"; String json2 = "{\"@class\":\"com.example.jackson.Teacher\",\"teacherName\":\"十佳教師~\",\"type\":null}"; System.out.println(objectMapper.readValue(json1, Person.class)); System.out.println(objectMapper.readValue(json2, Person.class)); }
輸出
{"@class":"com.example.jackson.Student","type":0,"studentName":"三好學(xué)生~"}
Student(studentName=三好學(xué)生~)
Teacher(teacherName=十佳教師~)
如果不想用@class做為類(lèi)型標(biāo)識(shí),也可使用簡(jiǎn)略模式
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) @Data public class Person { protected Integer type; }
測(cè)試
@Test void test2() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Student student = new Student(); student.setType(0); student.setStudentName("三好學(xué)生~"); System.out.println(objectMapper.writeValueAsString(student)); String json1 = "{\"@c\":\".Student\",\"studentName\":\"三好學(xué)生~\",\"type\":null}"; String json2 = "{\"@c\":\".Teacher\",\"teacherName\":\"十佳教師~\",\"type\":null}"; System.out.println(objectMapper.readValue(json1, Person.class)); System.out.println(objectMapper.readValue(json2, Person.class)); }
輸出
{"@c":".Student","type":0,"studentName":"三好學(xué)生~"}
Student(studentName=三好學(xué)生~)
Teacher(teacherName=十佳教師~)
2、通過(guò)屬性值判斷
上面的實(shí)體類(lèi)中,存在共同屬性,比如type就是一個(gè)共同屬性,可以通過(guò)這個(gè)共同屬性的值來(lái)判斷需要反序列化為哪一個(gè)類(lèi)。
如下,當(dāng)選擇屬性為type,當(dāng)值為1時(shí)反序列化為Student,值為2時(shí)反序列化為T(mén)eacher,值為3或4則反序列化為Doctor。
因?yàn)閠ype是類(lèi)中已存在的屬性,所以@JsonTypeInfo注解中的include屬性設(shè)置為EXISTING_PROPERTY,否則序列化的時(shí)候不管原先類(lèi)中有沒(méi)有type屬性,都會(huì)在序列化后的json中添加一個(gè)type,出現(xiàn)一個(gè)json中有兩個(gè)相同屬性的情況,這里就不貼出來(lái)了,感興趣可以自己去試一下。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true) @JsonSubTypes(value = { @JsonSubTypes.Type(value = Student.class, name = "1"), @JsonSubTypes.Type(value = Teacher.class, name = "2"), @JsonSubTypes.Type(value = Doctor.class, names = {"3", "4"}) }) @Data public class Person { protected Integer type; }
測(cè)試
@Test void test3() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Student student = new Student(); student.setType(1); student.setStudentName("三好學(xué)生~"); System.out.println(objectMapper.writeValueAsString(student)); String json1 = "{\"studentName\":\"三好學(xué)生~\",\"type\":1}"; String json2 = "{\"teacherName\":\"十佳教師~\",\"type\":2}"; String json3 = "{\"doctorName\":\"華佗在世~\",\"type\":4}"; System.out.println(objectMapper.readValue(json1, Person.class)); System.out.println(objectMapper.readValue(json2, Person.class)); System.out.println(objectMapper.readValue(json3, Person.class)); }
輸出
{"type":1,"studentName":"三好學(xué)生~"}
Student(studentName=三好學(xué)生~)
Teacher(teacherName=十佳教師~)
Doctor(doctorName=華佗在世~)
只不過(guò)使用這種方法有弊端,首先就是需要將涉及到反序列化的所有子類(lèi)都標(biāo)注到基類(lèi)上便于基類(lèi)感知,如果子類(lèi)多了,那就顯得臃腫,而且也違反了開(kāi)閉原則。所以介紹下面的另一種方式
通過(guò)屬性值判斷,除了上面的使用@JsonSubTypes在基類(lèi)上全都列出來(lái)之外,還可以使用@JsonTypeName注解標(biāo)注在子類(lèi)上,如下
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true) @Data public class Person { protected Integer type; }
@EqualsAndHashCode(callSuper = true) @Data @JsonTypeName("1") public class Student extends Person { private String studentName; }
其他幾個(gè)類(lèi)也是一樣,就不貼出來(lái)了。
測(cè)試
@Test void test4() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); // 關(guān)鍵的是這行 objectMapper.registerSubtypes(Student.class, Teacher.class, Doctor.class); Student student = new Student(); student.setType(1); student.setStudentName("三好學(xué)生~"); System.out.println(objectMapper.writeValueAsString(student)); String json1 = "{\"studentName\":\"三好學(xué)生~\",\"type\":1}"; String json2 = "{\"teacherName\":\"十佳教師~\",\"type\":2}"; String json3 = "{\"doctorName\":\"華佗在世~\",\"type\":3}"; System.out.println(objectMapper.readValue(json1, Person.class)); System.out.println(objectMapper.readValue(json2, Person.class)); System.out.println(objectMapper.readValue(json3, Person.class)); }
輸出
Student(studentName=三好學(xué)生~)
Teacher(teacherName=十佳教師~)
Doctor(doctorName=華佗在世~)
通過(guò)ObjectMapper的registerSubtypes方法注冊(cè)子類(lèi),這樣一來(lái)就不需要在基類(lèi)上標(biāo)注@JsonSubTypes注解了。
當(dāng)然,除了使用@JsonTypeName注解,然后直接注冊(cè)這個(gè)類(lèi)之外,還可以通過(guò)下面的方式進(jìn)行注冊(cè),效果是一樣的
objectMapper.registerSubtypes(new NamedType(Student.class, "1"));
上面的代碼是演示,所以在注冊(cè)時(shí)是一個(gè)個(gè)寫(xiě)死的,但實(shí)際上,不可能將所有類(lèi)全都寫(xiě)出來(lái)進(jìn)行注冊(cè),實(shí)際上可以借助一些工具進(jìn)行來(lái)獲取所有的子類(lèi),比如Reflections
<dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.10.2</version> </dependency>
// 獲取該路徑下所有類(lèi) Reflections reflections = new Reflections("com.example"); // 獲取對(duì)應(yīng)類(lèi)的所有子類(lèi) Set<Class<? extends Person>> classSet = reflections.getSubTypesOf(Person.class); for (Class<? extends Person> clazz : classSet) { // 將帶有@JsonTypeName注解的類(lèi)進(jìn)行注冊(cè) if (clazz.isAnnotationPresent(JsonTypeName.class)) { objectMapper.registerSubtypes(clazz); } }
到此這篇關(guān)于Java中Jackson的多態(tài)反序列化詳解的文章就介紹到這了,更多相關(guān)Jackson多態(tài)反序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡(jiǎn)單介紹一下什么是microservice微服務(wù)
這篇文章主要介紹了一下什么是microservice微服務(wù)微服務(wù)的定義,微服務(wù)到底是什么意思?什么樣的架構(gòu)可以叫做微服務(wù)?這篇文章可以給你答案2023-03-03java代碼塊之簡(jiǎn)易qq登錄界面及按鈕顏色設(shè)置代碼
這篇文章主要介紹了java代碼塊之簡(jiǎn)易qq登錄界面及按鈕顏色設(shè)置代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11基于javassist進(jìn)行動(dòng)態(tài)編程過(guò)程解析
這篇文章主要介紹了基于javassist進(jìn)行動(dòng)態(tài)編程過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05在Spring Boot中加載初始化數(shù)據(jù)的實(shí)現(xiàn)
這篇文章主要介紹了在Spring Boot中加載初始化數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02Java實(shí)現(xiàn)將Markdown轉(zhuǎn)換為純文本
這篇文章主要為大家詳細(xì)介紹了兩種在 Java 中實(shí)現(xiàn) Markdown 轉(zhuǎn)純文本的主流方法,文中的示例代碼講解詳細(xì),大家可以根據(jù)需求選擇適合的方案2025-03-03將java項(xiàng)目打包成exe可執(zhí)行文件的完整步驟
最近項(xiàng)目要求,需要將java項(xiàng)目生成exe文件,下面這篇文章主要給大家介紹了關(guān)于如何將java項(xiàng)目打包成exe可執(zhí)行文件的相關(guān)資料,文章通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06java基礎(chǔ)詳解之?dāng)?shù)據(jù)類(lèi)型知識(shí)點(diǎn)總結(jié)
這篇文章主要介紹了java基礎(chǔ)詳解之?dāng)?shù)據(jù)類(lèi)型知識(shí)點(diǎn)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很大的幫助,需要的朋友可以參考下2021-04-04java創(chuàng)建二維碼并賦予url鏈接的功能實(shí)現(xiàn)
這篇文章給大家分享java創(chuàng)建二維碼并賦予url鏈接的功能實(shí)現(xiàn),需要獲取要賦值給二維碼的鏈接后綴,通過(guò)設(shè)置二維碼的訪(fǎng)問(wèn)路徑等一系列操作,具體實(shí)現(xiàn)代碼跟隨小編一起看看吧2021-06-06