Java中Jackson的多態(tài)反序列化詳解
Jackson多態(tài)反序列化
多態(tài)序列化與反序列化,主要是借助于Jackson的@JsonTypeInfo與@JsonSubTypes注解實現(xiàn),下面將通過幾個例子來簡述其運用。
首先,創(chuàng)建幾個基本的實體類。這些類都比較簡單,有共同的屬性也有不同的屬性,這里為了簡單,共同屬性就只有一個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、通過類型判斷
在父類上加如下注解。因為是通過類型進行序列化,所以只需要加一個注解就夠了。
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@Data
public class Person {
protected Integer type;
}
測試
@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做為類型標識,也可使用簡略模式
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
@Data
public class Person {
protected Integer type;
}
測試
@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、通過屬性值判斷
上面的實體類中,存在共同屬性,比如type就是一個共同屬性,可以通過這個共同屬性的值來判斷需要反序列化為哪一個類。
如下,當(dāng)選擇屬性為type,當(dāng)值為1時反序列化為Student,值為2時反序列化為Teacher,值為3或4則反序列化為Doctor。
因為type是類中已存在的屬性,所以@JsonTypeInfo注解中的include屬性設(shè)置為EXISTING_PROPERTY,否則序列化的時候不管原先類中有沒有type屬性,都會在序列化后的json中添加一個type,出現(xiàn)一個json中有兩個相同屬性的情況,這里就不貼出來了,感興趣可以自己去試一下。
@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;
}
測試
@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=華佗在世~)
只不過使用這種方法有弊端,首先就是需要將涉及到反序列化的所有子類都標注到基類上便于基類感知,如果子類多了,那就顯得臃腫,而且也違反了開閉原則。所以介紹下面的另一種方式
通過屬性值判斷,除了上面的使用@JsonSubTypes在基類上全都列出來之外,還可以使用@JsonTypeName注解標注在子類上,如下
@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;
}
其他幾個類也是一樣,就不貼出來了。
測試
@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=華佗在世~)
通過ObjectMapper的registerSubtypes方法注冊子類,這樣一來就不需要在基類上標注@JsonSubTypes注解了。
當(dāng)然,除了使用@JsonTypeName注解,然后直接注冊這個類之外,還可以通過下面的方式進行注冊,效果是一樣的
objectMapper.registerSubtypes(new NamedType(Student.class, "1"));
上面的代碼是演示,所以在注冊時是一個個寫死的,但實際上,不可能將所有類全都寫出來進行注冊,實際上可以借助一些工具進行來獲取所有的子類,比如Reflections
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
// 獲取該路徑下所有類
Reflections reflections = new Reflections("com.example");
// 獲取對應(yīng)類的所有子類
Set<Class<? extends Person>> classSet = reflections.getSubTypesOf(Person.class);
for (Class<? extends Person> clazz : classSet) {
// 將帶有@JsonTypeName注解的類進行注冊
if (clazz.isAnnotationPresent(JsonTypeName.class)) {
objectMapper.registerSubtypes(clazz);
}
}
到此這篇關(guān)于Java中Jackson的多態(tài)反序列化詳解的文章就介紹到這了,更多相關(guān)Jackson多態(tài)反序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java代碼塊之簡易qq登錄界面及按鈕顏色設(shè)置代碼
這篇文章主要介紹了java代碼塊之簡易qq登錄界面及按鈕顏色設(shè)置代碼,具有一定參考價值,需要的朋友可以了解下。2017-11-11
在Spring Boot中加載初始化數(shù)據(jù)的實現(xiàn)
這篇文章主要介紹了在Spring Boot中加載初始化數(shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Java實現(xiàn)將Markdown轉(zhuǎn)換為純文本
這篇文章主要為大家詳細介紹了兩種在 Java 中實現(xiàn) Markdown 轉(zhuǎn)純文本的主流方法,文中的示例代碼講解詳細,大家可以根據(jù)需求選擇適合的方案2025-03-03
java基礎(chǔ)詳解之?dāng)?shù)據(jù)類型知識點總結(jié)
這篇文章主要介紹了java基礎(chǔ)詳解之?dāng)?shù)據(jù)類型知識點總結(jié),文中有非常詳細的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很大的幫助,需要的朋友可以參考下2021-04-04
java創(chuàng)建二維碼并賦予url鏈接的功能實現(xiàn)
這篇文章給大家分享java創(chuàng)建二維碼并賦予url鏈接的功能實現(xiàn),需要獲取要賦值給二維碼的鏈接后綴,通過設(shè)置二維碼的訪問路徑等一系列操作,具體實現(xiàn)代碼跟隨小編一起看看吧2021-06-06

