Jackson 自定义序列化程序:将对象更改为简单的 属性 和包含对象中的值
Jackson custom serializer: change object to be a simple property and value in containing object
我遇到的问题是我有一个在很多地方使用的公共对象,在这个例子中,公共对象是 Student。 Student 是另一个名为 Enrollment 的对象的 属性(但它可能是许多其他 classes 的 属性)。现在,如果没有将自定义序列化应用于 Student,我将得到如下内容:
{"session":"星期三上午 9 点","student":{"firstName":"Joe","lastName":"Bloggs"}}
我想做的是将自定义序列化程序应用于 Student,以便它出现在我的代码中的任何位置,例如在本例中它在 Enrollment class 中,我将得到这个:
{"session":"星期三上午 9 点","firstName":"Joe","lastName":"Bloggs"}
或者如果我这样选择:
{"session":"星期三上午 9 点","first":"Joe","last":"Bloggs"}
或者甚至是这样:
{"session":"星期三上午 9 点","name":"Joe Bloggs"}
这是我的示例代码:
public class Enrolment {
private String session;
private Student student;
public Enrolment(String session, Student student) {
this.session = session;
this.student = student;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
@JsonSerialize(using = StudentSerializer.class)
public class Student {
private String firstName;
private String lastName;
public Student(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class StudentSerializer extends JsonSerializer<Student> {
@Override
public void serialize(Student value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
// ??????
}
}
public class Launcher {
public static void main(String[] args) throws Exception{
ObjectMapper mapper = new ObjectMapper();
Student student = new Student("Joe", "Bloggs");
Enrolment enrolment = new Enrolment("9am Wednesday", student);
System.out.println(mapper.writeValueAsString(enrolment));
}
}
如果您也可以提供一个反序列化器以便它可以接受所需的 json 序列化示例之一并从中创建 Student 对象,那将是一个巨大的好处。同样,反序列化器就像序列化器一样必须附加到 Student 对象,以便它出现在任何地方都将执行相同的操作。
谢谢:)
您希望从 1.9 版开始使用 @JsonUnwrapped
注释。您可以查看 2.0 版的文档 here,但基本上您会:
public class Enrolment {
...
@JsonUnwrapped
public Student getStudent() {
return student;
}
...
}
你会得到第一个选项:
{"session":"9am Wednesday","firstName":"Joe","lastName":"Bloggs"}
注释依赖于默认序列化程序。一方面,您不能为 Student
使用自定义序列化程序,但另一方面,您可以使用其他注释,如 @JsonProperty
并自定义 Student
以获得第二个选项。
您的第三个选项最好通过在 Student
中添加自定义 getter 和 setter 来完成。在这种情况下,您将使用 @JsonIgnore
来避免序列化其他属性。
这是我偶然发现的另一个选项:
public class Enrolment {
private String session;
private Student student;
public Enrolment(String session, Student student) {
this.session = session;
this.student = student;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
@JsonUnwrapped
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
public class StudentUnwrappingBeanSerializer extends UnwrappingBeanSerializer {
public StudentUnwrappingBeanSerializer(BeanSerializerBase src, NameTransformer transformer) {
super(src, transformer);
}
@Override
public JsonSerializer<Object> unwrappingSerializer(NameTransformer transformer) {
return new StudentUnwrappingBeanSerializer(this, transformer);
}
@Override
protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
Student student = (Student) bean;
jgen.writeStringField("first", student.getFirstName());
jgen.writeStringField("last", student.getLastName());
}
@Override
public boolean isUnwrappingSerializer() {
return true;
}
}
public class Launcher {
public static void main(String[] args) throws Exception{
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Module() {
@Override
public String getModuleName() {
return "my.module";
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if(beanDesc.getBeanClass().equals(Student.class)) {
return new StudentUnwrappingBeanSerializer((BeanSerializerBase) serializer, NameTransformer.NOP);
}
return serializer;
}
});
}
});
Student student = new Student("Joe", "Bloggs");
ExtendableOption<StudyType> studyType = new ExtendableOption<>(StudyType.DISTANCE);
Enrolment enrolment = new Enrolment("9am Wednesday", student, studyType);
System.out.println(mapper.writeValueAsString(enrolment));
}
}
我遇到的问题是我有一个在很多地方使用的公共对象,在这个例子中,公共对象是 Student。 Student 是另一个名为 Enrollment 的对象的 属性(但它可能是许多其他 classes 的 属性)。现在,如果没有将自定义序列化应用于 Student,我将得到如下内容:
{"session":"星期三上午 9 点","student":{"firstName":"Joe","lastName":"Bloggs"}}
我想做的是将自定义序列化程序应用于 Student,以便它出现在我的代码中的任何位置,例如在本例中它在 Enrollment class 中,我将得到这个:
{"session":"星期三上午 9 点","firstName":"Joe","lastName":"Bloggs"}
或者如果我这样选择:
{"session":"星期三上午 9 点","first":"Joe","last":"Bloggs"}
或者甚至是这样:
{"session":"星期三上午 9 点","name":"Joe Bloggs"}
这是我的示例代码:
public class Enrolment {
private String session;
private Student student;
public Enrolment(String session, Student student) {
this.session = session;
this.student = student;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
@JsonSerialize(using = StudentSerializer.class)
public class Student {
private String firstName;
private String lastName;
public Student(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class StudentSerializer extends JsonSerializer<Student> {
@Override
public void serialize(Student value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
// ??????
}
}
public class Launcher {
public static void main(String[] args) throws Exception{
ObjectMapper mapper = new ObjectMapper();
Student student = new Student("Joe", "Bloggs");
Enrolment enrolment = new Enrolment("9am Wednesday", student);
System.out.println(mapper.writeValueAsString(enrolment));
}
}
如果您也可以提供一个反序列化器以便它可以接受所需的 json 序列化示例之一并从中创建 Student 对象,那将是一个巨大的好处。同样,反序列化器就像序列化器一样必须附加到 Student 对象,以便它出现在任何地方都将执行相同的操作。
谢谢:)
您希望从 1.9 版开始使用 @JsonUnwrapped
注释。您可以查看 2.0 版的文档 here,但基本上您会:
public class Enrolment {
...
@JsonUnwrapped
public Student getStudent() {
return student;
}
...
}
你会得到第一个选项:
{"session":"9am Wednesday","firstName":"Joe","lastName":"Bloggs"}
注释依赖于默认序列化程序。一方面,您不能为 Student
使用自定义序列化程序,但另一方面,您可以使用其他注释,如 @JsonProperty
并自定义 Student
以获得第二个选项。
您的第三个选项最好通过在 Student
中添加自定义 getter 和 setter 来完成。在这种情况下,您将使用 @JsonIgnore
来避免序列化其他属性。
这是我偶然发现的另一个选项:
public class Enrolment {
private String session;
private Student student;
public Enrolment(String session, Student student) {
this.session = session;
this.student = student;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
@JsonUnwrapped
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
public class StudentUnwrappingBeanSerializer extends UnwrappingBeanSerializer {
public StudentUnwrappingBeanSerializer(BeanSerializerBase src, NameTransformer transformer) {
super(src, transformer);
}
@Override
public JsonSerializer<Object> unwrappingSerializer(NameTransformer transformer) {
return new StudentUnwrappingBeanSerializer(this, transformer);
}
@Override
protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
Student student = (Student) bean;
jgen.writeStringField("first", student.getFirstName());
jgen.writeStringField("last", student.getLastName());
}
@Override
public boolean isUnwrappingSerializer() {
return true;
}
}
public class Launcher {
public static void main(String[] args) throws Exception{
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Module() {
@Override
public String getModuleName() {
return "my.module";
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if(beanDesc.getBeanClass().equals(Student.class)) {
return new StudentUnwrappingBeanSerializer((BeanSerializerBase) serializer, NameTransformer.NOP);
}
return serializer;
}
});
}
});
Student student = new Student("Joe", "Bloggs");
ExtendableOption<StudyType> studyType = new ExtendableOption<>(StudyType.DISTANCE);
Enrolment enrolment = new Enrolment("9am Wednesday", student, studyType);
System.out.println(mapper.writeValueAsString(enrolment));
}
}