简体   繁体   中英

How to filter attributes from JSON response in spring?

I have a controller like the following,

@RequestMapping(value = "rest/v1/tester")
public class TestController {

    @RequestMapping(value = "/search", method = RequestMethod.GET)
    public ResponseEntity<SampleResults> search(@ModelAttribute("criteria")SampleCriteria criteria) throws Exception {
            SampleResults sampleResults = sampleService.search(criteria);
            return new ResponseEntity<>(sampleResults, OK);
    }

}

I have another controller like so,

@RequestMapping(value = "rest/v1/second")
public class SecondTestController {

@RequestMapping(value = "/search", method = RequestMethod.GET)
    public ResponseEntity<SampleResults> search(@ModelAttribute("criteria")SampleCriteria criteria) throws Exception {
            SampleResults sampleResults = secondsampleService.search(criteria);
            return new ResponseEntity<>(sampleResults, OK);
    }

}

The structure of my result is as follows:

public class SampleResults extends Results<SearchSummary, Sample> {
}

This extends from the result class:

public class Results<SUMMARY,RESULTS> {
    private SUMMARY summary;
    private List<RESULTS> results;

    /*Constructors, getters and setters*/
}

Now the model that I am going to set into the results field is,

@JsonDeserialize(as = SampleImpl.class)
public interface Sample {

    Long getId();
    void setId(Long id);

    String getName();
    void setName(String name);

    int getAge();
    void setAge(int age);

}

public class SampleImpl implements Sample {

    private Long id;
    private String name;
    private int age;

    /* Getters and Setters */

}

Now for the TestController mentioned above, I would like to display all the fields in the json response, whereas in the SecondTestController I would like to mask (not show) the age attribute in the json response. How can I achieve this in spring. Any help greatly appreciated!

Have you considered @JsonView ?

It is supported by Spring MVC and allows you to filter fields depending on the context of serialization.

First define your views:

public class View {     

    interface SampleView { }  
    interface SampleViewWithAge extends SampleView { }   
}

Then annotate your fields using the desired view:

public class SampleImpl implements Sample { 

    @JsonView(View.SampleView.class)
    private Long id; 

    @JsonView(View.SampleView.class)
    private String name; 

    @JsonView(View.SampleViewWithAge.class)
    private int age;

    // Getters and setters
 }

Finally annotate your handlers to use a view when serializing the response:

@JsonView(View.SampleView.class) 
@RequestMapping(value = "/search", method = RequestMethod.GET)  
public ResponseEntity<SampleResults> search() {
    ... 
}

@JsonView(View.SampleViewWithAge.class)
@RequestMapping(value = "/search", method = RequestMethod.GET)  
public ResponseEntity<SampleResults> searchWithAge() {
    ... 
}

I think the most simple way to do that is to use Jackson @JsonFilter if you want it dynamic.

For instance, here could be an exemple with Spring Boot :

Your document :

@JsonFilter("myFilter")
class Document {
   private field1;
   private field2;
}

Modify your default configured HttpMessageConverter :

@Configuration
class WebMvcConfiguration extends WebMvcConfigurationSupport {
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for(HttpMessageConverter<?> converter: converters) {
            if(converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter)converter).getObjectMapper();
                mapper.setFilterProvider(new SimpleFilterProvider().addFilter("myFilter", SimpleBeanPropertyFilter.serializeAll()));
            }
        }
    }
}

This Filter will serialize all by default. This step is mandatory, if you don't specify it, you will have an exception coming that he does not know myFilter when your controller will try to generate an object response.

Then, in you controller, here is your regular endpoint that serialize all field (using the previously declared filter):

@RequestMapping(value = "path/document", method = RequestMethod.GET)
public Document getDocumentWithAllFields() {
   return new Document("val1","val2");
} 
//result : {"field1":"val1","field2":"val2"}

And now, the endpoint to have the same object with only some fields serialized :

@RequestMapping(value = "path/document", method = RequestMethod.GET)
public MappingJacksonValue getDocumentWithSomeFields(@RequestParam String[] fields) {
    MappingJacksonValue wrapper = new MappingJacksonValue(new Document("val1","val2"));
    FilterProvider filterProvider = new SimpleFilterProvider().addFilter("myFilter", 
         SimpleBeanPropertyFilter.filterOutAllExcept(fields)); 
    wrapper.setFilters(filterProvider);
    return wrapper;
} 
//result : {"field1":"val1"} (with 'fields' being a coma separated list, containing here just "field1"

Override toString method in your modal class with required fields and convert it to json explicitly as below in your second controller method.

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
//get yourObject

ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(yourObject);

public class BeanFilterCustom {

public Object filterBean(Object object,String someBeanFilter)  {

    SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("","");
    FilterProvider filters = new SimpleFilterProvider()
            .addFilter(someBeanFilter, filter);
    MappingJacksonValue mapping = new MappingJacksonValue(object);
    mapping.setFilters(filters);
    return mapping.getValue();
}

}

You can use @JsonIgnore on fields you don't want to be included in your JSON.

public class SampleImpl implements Sample {

    private Long id;
    private String name;

    @JsonIgnore
    private int age;

    /* Getters and Setters */

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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