如何动态忽略Jackson序列化的属性

时间:2018-07-04 11:22:57

标签: json spring-boot serialization jackson

我有一个具有多个@ManyToOne关联的实体。我正在使用spring-boot应用程序公开REST API。目前,我有多个REST API,它们返回包括关联在内的整个实体的json响应。

但是我不想序列化所有REST API中的所有关联对象。例如

API-1应该返回父对象+ associationA对象 API-2应该返回父对象+ associationA + associationB对象 API-3应该返回parent + associationB + associationc + associationD

因此,在我的序列化过程中,我想忽略除API-1的associationA以外的所有关联。 对于API-2,我想忽略A和B以外的其他关联

如何在Jackson序列化过程中动态忽略这些属性。

注意: 我在同一个班上,我不想为每个API创建任何dto

任何建议都会受到赞赏。

2 个答案:

答案 0 :(得分:7)

我汇总了三种在Jackson中执行动态过滤的方法。其中之一必须满足您的需求。

使用@JsonView

您可以使用@JsonView

public class Views {         
    interface Simple { }  
    interface Detailed extends Simple { }   
}
public class Foo {

    @JsonView(Views.Simple.class)
    private String name;

    @JsonView(Views.Detailed.class)
    private String details;

    // Getters and setters
}
@RequestMapping("/foo")
@JsonView(Views.Detailed.class)
public Foo getFoo() {
    Foo foo = new Foo();
    return foo;
}

或者,您可以使用MappingJacksonValue动态设置视图。

@RequestMapping("/foo")
public MappingJacksonValue getFoo() {
    Foo foo = new Foo();
    MappingJacksonValue result = new MappingJacksonValue(foo);
    result.setSerializationView(Views.Detailed.class);
    return result;
}

使用BeanSerializerModifier

您可以扩展BeanSerializerModifier,然后覆盖changeProperties()方法。它允许您根据需要添加,删除或替换任何要序列化的属性:

public class CustomSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
        BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {

        // In this method you can add, remove or replace any of passed properties

        return beanProperties;
    }
}

然后将序列化程序注册为ObjectMapper中的模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule() {

    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        context.addBeanSerializerModifier(new CustomSerializerModifier());
    }
});

检查示例herehere

@JsonFilterSimpleBeanPropertyFilter一起使用

另一种方法涉及@JsonFilter

@JsonFilter("customPropertyFilter")
public class Foo {

    private String name;
    private String details;

    // Getters and setters
}

根据您的需要扩展SimpleBeanPropertyFilter并覆盖serializeAsField()方法:

public class CustomPropertyFilter extends SimpleBeanPropertyFilter {

    @Override
    public void serializeAsField(Object pojo, JsonGenerator jgen,
                                 SerializerProvider provider, 
                                 PropertyWriter writer) throws Exception {

        // Serialize a field
        // writer.serializeAsField(pojo, jgen, provider, writer);

        // Omit a field from serialization
        // writer.serializeAsOmittedField(pojo, jgen, provider);
    }
}

然后在您的ObjectMapper中注册过滤器:

FilterProvider filterProvider = new SimpleFilterProvider()
        .addFilter("customPropertyFilter", new CustomPropertyFilter());

ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);

如果要将过滤器设置为“全局” ,即要应用于所有bean,则可以创建一个混合类并用@JsonFilter("customPropertyFilter")进行注释:< / p>

@JsonFilter("customPropertyFilter")
public class CustomPropertyFilterMixIn {

}

然后将混合类绑定到Object

mapper.addMixIn(Object.class, CustomPropertyFilterMixIn.class);

答案 1 :(得分:0)

我已经对从 db 获取的数据实施动态过滤器并使用 rest api 返回它。我避免使用 MappingJacksonValue。因为它在对象链接时出现问题

@GetMapping("/courses")
    public ResponseEntity<JpaResponse> allCourse() throws Exception {
        JpaResponse response = null;
         ObjectMapper mapper = new ObjectMapper(); 
         mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        List<Course> course = service.findAllCourse();
        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("name","reviews");
        FilterProvider filterProvider = new SimpleFilterProvider().addFilter("jpafilter", filter).setFailOnUnknownId(false);
                ObjectWriter writer = mapper.writer(filterProvider);
        String writeValueAsString = writer.writeValueAsString(course);
        List<Course> resultcourse = mapper.readValue(writeValueAsString,List.class);
            response = new JpaResponse(HttpStatus.OK.name(),resultcourse);
            return new ResponseEntity<>(response, HttpStatus.OK);

}

public class JpaResponse {
        private String status;
        private Object data;
        public JpaResponse() {
            super();
        }
        public JpaResponse(String status, Object data) {
            super();
            this.status = status;
            this.data = data;
        }
}