Jackson多态反序列化
创始人
2024-01-22 17:04:57
0

多态序列化与反序列化,主要是借助于Jackson的@JsonTypeInfo@JsonSubTypes注解实现,下面将通过几个例子来简述其运用。

首先,创建几个基本的实体类。这些类都比较简单,有共同的属性也有不同的属性,这里为了简单,共同属性就只有一个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("三好学生~");System.out.println(objectMapper.writeValueAsString(student));String json1 = "{\"@class\":\"com.example.jackson.Student\",\"studentName\":\"三好学生~\",\"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":"三好学生~"}
Student(studentName=三好学生~)
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("三好学生~");System.out.println(objectMapper.writeValueAsString(student));String json1 = "{\"@c\":\".Student\",\"studentName\":\"三好学生~\",\"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":"三好学生~"}
Student(studentName=三好学生~)
Teacher(teacherName=十佳教师~)

2、通过属性值判断

上面的实体类中,存在共同属性,比如type就是一个共同属性,可以通过这个共同属性的值来判断需要反序列化为哪一个类。

如下,当选择属性为type,当值为1时反序列化为Student,值为2时反序列化为Teacher,值为3或4则反序列化为Doctor

因为type是类中已存在的属性,所以@JsonTypeInfo注解中的include属性设置为EXISTING_PROPERTY,否则序列化的时候不管原先类中有没有type属性,都会在序列化后的json中添加一个type,出现一个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("三好学生~");System.out.println(objectMapper.writeValueAsString(student));String json1 = "{\"studentName\":\"三好学生~\",\"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":"三好学生~"}
Student(studentName=三好学生~)
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();// 关键的是这行objectMapper.registerSubtypes(Student.class, Teacher.class, Doctor.class);Student student = new Student();student.setType(1);student.setStudentName("三好学生~");System.out.println(objectMapper.writeValueAsString(student));String json1 = "{\"studentName\":\"三好学生~\",\"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=三好学生~)
Teacher(teacherName=十佳教师~)
Doctor(doctorName=华佗在世~)

通过ObjectMapperregisterSubtypes方法注册子类,这样一来就不需要在基类上标注@JsonSubTypes注解了。

当然,除了使用@JsonTypeName注解,然后直接注册这个类之外,还可以通过下面的方式进行注册,效果是一样的

objectMapper.registerSubtypes(new NamedType(Student.class, "1"));

上面的代码是演示,所以在注册时是一个个写死的,但实际上,不可能将所有类全都写出来进行注册,实际上可以借助一些工具进行来获取所有的子类,比如Reflections

org.reflectionsreflections0.10.2

// 获取该路径下所有类
Reflections reflections = new Reflections("com.example");
// 获取对应类的所有子类
Set> classSet = reflections.getSubTypesOf(Person.class);
for (Class clazz : classSet) {// 将带有@JsonTypeName注解的类进行注册if (clazz.isAnnotationPresent(JsonTypeName.class)) {objectMapper.registerSubtypes(clazz);}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...