【问题标题】:Jackson custom serializer: change object to be a simple property and value in containing objectJackson 自定义序列化器:将对象更改为包含对象的简单属性和值
【发布时间】:2015-07-03 12:44:28
【问题描述】:

我遇到的问题是我有一个在很多地方都使用的公共对象,在这个例子中,公共对象是学生。 Student 是另一个名为 Enrollment 的对象的属性(但是它可能是许多其他类的属性)。现在,如果没有对 Student 应用自定义序列化,我会得到这样的结果:

{"session":"9am Wednesday","student":{"firstName":"Joe","lastName":"Bloggs"}}

我想做的是为 Student 应用一个自定义序列化程序,以便它出现在我的代码中的任何地方,例如在这个例子中它在 Enrollment 类中,我会得到这个:

{"session":"9am Wednesday","firstName":"Joe","lastName":"Bloggs"}

或者如果我这样选择:

{"session":"9am Wednesday","first":"Joe","last":"Bloggs"}

或者甚至是这样:

{"session":"9am Wednesday","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 对象,以便它出现的任何地方都会执行相同的操作。

谢谢你:)

【问题讨论】:

    标签: java json serialization jackson deserialization


    【解决方案1】:

    您希望 @JsonUnwrapped 注释从 1.9 版开始可用。您可以查看版本 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 来避免序列化其他属性。

    【讨论】:

      【解决方案2】:

      这是我偶然发现的另一个选择:

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

      【讨论】:

        猜你喜欢
        • 2018-06-18
        • 1970-01-01
        • 2020-10-29
        • 1970-01-01
        • 2016-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多