Search code examples
javaspring-bootjacksonspring-resthateoas

Dynamic filtering of a field in the response from a RESTful webservice enpoint that returns a List of domain objects


Given a RESTful web service developed using the Spring Boot framework, I wanted a way to suppress the birthDate of all Users in the response. This is what I implemented after looking around for a solution :

@RestController
public class UserResource {

    @Autowired
    private UserDAOservice userDAOService;

    @GetMapping("/users")
    public MappingJacksonValue users() {
        List<User> users = userDAOService.findAll();

        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
                .filterOutAllExcept("id", "name");

        FilterProvider filters = new SimpleFilterProvider().addFilter(
                "UserBirthDateFilter", filter);

        MappingJacksonValue mapping = new MappingJacksonValue(users);

        mapping.setFilters(filters);

        return mapping;
    }
}

However, when I hit the rest end point in the browser, I can still see the birth date of the user in the response :

{
    "id": 1,
    "name": "Adam",
    "birthDate": "1980-03-31T16:56:28.926+0000"
}

Question 1 : What API can I use to achieve my objective?

Next, assuming that I want to adhere to HATEOAS in combination with filtering, how can I go about doing this. I am unable to figure out the APIs that can be used for using these two features together :

@GetMapping("/users/{id}")
public EntityModel<User> users(@PathVariable Integer id) {
    User user = userDAOService.findById(id);
    if (user == null) {
        throw new ResourceNotFoundException("id-" + id);
    }

    EntityModel<User> model = new EntityModel<>(user);
    WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).users());
    model.add(linkTo.withRel("all-users"));

    //how do I combine EntityModel with filtering?
    return model;
}

Question 2 : How do I combine EntityModel with MappingJacksonValue?

Note : I am aware of @JsonIgnore annotation but that would apply the filter for all end points that use the domain; however, I want to restrict the filtering only to the two endpoints above.


Solution

  • Turns out for this to work, I have to add the @JsonFilter annotation above the DTO and provide the same name that was used while creating the SimpleFilterProvider.

    @JsonFilter("UserBirthDateFilter")
    public class User {
    
        private Integer id;
    
    
        @Size(min=2, message="user name must be atleast 2 characters")
        @ApiModelProperty(notes="user name must be atleast 2 characters")
        private String name;
    
        @Past
        @ApiModelProperty(notes="birth date cannot be in the past")
        private Date birthDate;
    
       //other methods
    }