繁体   English   中英

Jackson 用于嵌套字段序列化的多个不同模式

[英]Jackson multiple different schema for serialization of nested fields

使用 Jackson 进行序列化时,我希望有几种不同的模式。 假设我有以下课程:

public class Department {
      private Person head;
      private Person deputy;
      private List<Person> staff;
      // getters and setters
}

public class Person {
       private String name
       private int code;
      // getters and setters
}

现在,我想为Department class 提供两种不同的架构。 第一个只包含headdeputy ,其中head包括namecode ,但deputy只有name 第二个模式应该递归地包含所有字段。

因此,我们将有两个不同的 json。 使用第一个模式:

{
    "head" : {
        "name" : "John",
        "code" : 123
     },
     "deputy" : { 
        "name" : "Jack"
     } 
}

,并使用第二个模式:

{
    "head" : {
        "name" : "John",
        "code" : 123
     },
     "deputy" : { 
        "name" : "Jack",
        "code" : "234"
     },
     "staff": [
        { 
            "name" : "Tom",
            "code" : "345"
         },
         { 
            "name" : "Matt",
            "code" : "456"
         },
     ]
}

问题:我应该如何处理 Jackson?

注意:这些类只是示例。 对于这个简单的示例,编写四个不同的包装类可能是可能的,但考虑一个包含十几个类的复杂示例,每个类都有多个字段。 使用包装类,我们应该生成很多样板代码。

任何帮助,将不胜感激!

尽管@bigbounty 解决方案非常好,而且我认为除了特定的DTO之外, View通常是通往 go 的方式,但在这种情况下它可能不适用,因为对于同一个 class Person ,我们实际上需要两种不同的行为在同一个视图中。

@JsonFilter可以用来解决问题。

这个main方法计算你需要的图表:


  public static void main(String[] args) throws JsonProcessingException {

    final PropertyFilter departmentFilter = new SimpleBeanPropertyFilter() {
      @Override
      public void serializeAsField
        (Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
        throws Exception {
        if (include(writer)) {
          final String name = writer.getName();
          if (!name.equals("deputy") && !name.equals("staff")) {
            writer.serializeAsField(pojo, jgen, provider);
            return;
          }

          if (name.equals("staff")) {
            return;
          }

          // Ideally it should not be muted.
          final Department department = (Department)pojo;
          final Person deputy = department.getDeputy();
          deputy.setCode(-1);

          writer.serializeAsField(department, jgen, provider);

        } else if (!jgen.canOmitFields()) { // since 2.3
          writer.serializeAsOmittedField(pojo, jgen, provider);
        }
      }
      @Override
      protected boolean include(BeanPropertyWriter writer) {
        return true;
      }
      @Override
      protected boolean include(PropertyWriter writer) {
        return true;
      }
    };

    final PropertyFilter personFilter = new SimpleBeanPropertyFilter() {

      @Override
      public void serializeAsField
        (Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
        throws Exception {
        if (include(writer)) {
          if (!writer.getName().equals("code")) {
            writer.serializeAsField(pojo, jgen, provider);
            return;
          }

          int code = ((Person) pojo).getCode();
          if (code >= 0) {
            writer.serializeAsField(pojo, jgen, provider);
          }
        } else if (!jgen.canOmitFields()) { // since 2.3
          writer.serializeAsOmittedField(pojo, jgen, provider);
        }
      }
      @Override
      protected boolean include(BeanPropertyWriter writer) {
        return true;
      }
      @Override
      protected boolean include(PropertyWriter writer) {
        return true;
      }
    };

    final Department department = new Department();
    final Person head = new Person("John", 123);
    final Person deputy = new Person("Jack", 234);
    final List<Person> personList = Arrays.asList(new Person("Tom", 345), new Person("Matt", 456));
    department.setHead(head);
    department.setDeputy(deputy);
    department.setStaff(personList);

    final ObjectMapper mapper = new ObjectMapper();

    final FilterProvider schema1Filters = new SimpleFilterProvider()
      .addFilter("deparmentFilter", departmentFilter)
      .addFilter("personFilter", personFilter)
      ;

    mapper.setFilterProvider(schema1Filters);

    final String withSchema1Filters = mapper.writeValueAsString(department);
    System.out.printf("Schema 1:\n%s\n", withSchema1Filters);

    // You must maintain the filters once the classes are annotated with @JsonFilter
    // We can use two no-op builtin filters
    final FilterProvider schema2Filters = new SimpleFilterProvider()
      .addFilter("deparmentFilter", SimpleBeanPropertyFilter.serializeAll())
      .addFilter("personFilter", SimpleBeanPropertyFilter.serializeAll())
      ;

    mapper.setFilterProvider(schema2Filters);

    final String withSchema2Filters = mapper.writeValueAsString(department);
    System.out.printf("Schema 2:\n%s\n", withSchema2Filters);
  }

要使此代码正常工作,您必须使用以下内容注释Department class:

@JsonFilter("deparmentFilter")

还有Person class :

@JsonFilter("personFilter")

如您所见,Jackson 还提供了几个内置过滤器。

此代码与您提出的测试类非常耦合,但可以以使其更通用的方式进行扩展。

请查看SimpleBeanPropertyFilter以获取有关如何创建自己的过滤器的示例。

Jackson 库中有一个功能 JsonViews。

您需要有一个 class 的意见

public class Views {

    public static class Normal{}

    public static class Extended extends Normal{}

}

接下来你注释系class

import com.fasterxml.jackson.annotation.JsonView;

import java.util.List;

public class Department {

    @JsonView(Views.Normal.class)
    private Person head;

    @JsonView(Views.Normal.class)
    private Person deputy;

    @JsonView(Views.Extended.class)
    private List<Person> staff;

    public Person getHead() {
        return head;
    }

    public void setHead(Person head) {
        this.head = head;
    }

    public Person getDeputy() {
        return deputy;
    }

    public void setDeputy(Person deputy) {
        this.deputy = deputy;
    }

    public List<Person> getStaff() {
        return staff;
    }

    public void setStaff(List<Person> staff) {
        this.staff = staff;
    }
}

保持人 class 原样

public class Person {
    private String name;
    private int code;

    public Person(String name, int code) {
        this.name = name;
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}

在主function中,你在序列化object的地方,需要开启相应的视图。

public class Main {


    static Department createDepartment(){
        Department department = new Department();
        Person head = new Person("John", 123);
        Person deputy = new Person("Jack", 234);
        List<Person> personList = Arrays.asList(new Person("Tom", 345), new Person("Matt", 456));
        department.setHead(head);
        department.setDeputy(deputy);
        department.setStaff(personList);
        return department;

    }

    public static void main(String[] args) throws JsonProcessingException {

        Department department = createDepartment();

        ObjectMapper mapper = new ObjectMapper();

        String normal = mapper.writerWithView(Views.Normal.class).writeValueAsString(department);
        String extended = mapper.writerWithView(Views.Extended.class).writeValueAsString(department);

        System.out.println("Normal View - " + normal);
        System.out.println("Extended View - " + extended);
   }
}

output如下:

Normal View - {"head":{"name":"John","code":123},"deputy":{"name":"Jack","code":234}}
Extended View - {"head":{"name":"John","code":123},"deputy":{"name":"Jack","code":234},"staff":[{"name":"Tom","code":345},{"name":"Matt","code":456}]}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM