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));

  }
}