I'm implementing REST partial updates with PATCH, for example:

    @PatchMapping(PATH_DETAIL)
    public User updatePartial(@PathVariable Long id,
            @RequestBody @JsonView(User.View.Updatable.class) @Valid User user) {
        return userRepository.findById(id).map(u -> {
            BeanUtils.copyNonNullProperties(user, u);
            return userRepository.save(u);
        }).orElseThrow(() -> notFound(id));
    }

currently there is no way to differ {"username":"test","password":null} (set password to null) with {"username":"test"} (ignore password), I wish Spring Boot provide an annotation like @PresentedFields

    @PatchMapping(PATH_DETAIL)
    public User updatePartial(@PathVariable Long id,
            @RequestBody @JsonView(User.View.Updatable.class) @Valid User user,@PresentedFields Set<String> fields) {
        //fields contains username and password even if password is null
    }

or some other mechanism.

Comment From: quaff

My proposal is considering reuse BindingResult, add a method such as getBindingPropertyNames returning Collection<String>

public User updatePartial(@PathVariable Long id, @RequestBody @Valid User user, BindingResult result) {
// result.getBindingPropertyNames()
}

Comment From: snicoll

Thanks for the suggestion, but given the copy bit there, why don't you inject a Map of attribute, rather than the mapped object? This would provide the presence of fields and is certainly a more straightforward way to accomplish this rather than us providing yet another annotation.

Comment From: quaff

Thanks for the suggestion, but given the copy bit there, why don't you inject a Map of attribute, rather than the mapped object? This would provide the presence of fields and is certainly a more straightforward way to accomplish this rather than us providing yet another annotation.

The drawback of Map is that it couldn't retain type of mapped object. I'm against introducing another annotation now, please reconsider my proposal about BindingResult.

Comment From: poutsma

In Spring MVC, there are two mechanisms for transforming request data into an object.

  • There is binding, where submitted HTML form parameter values are copied to object properties, using Spring DataBinder functionality.
  • And there is @RequestBody, where any kind of request data can be transformed into an object, using the Spring HttpMessageConverter abstraction. Specifically, you are using the MappingJackson2HttpMessageConverter which uses Jackson to transform the submitted JSON to the desired object.

When reading JSON with @RequestBody, you are using the second mechanism. BindingResult belongs to the first mechanism, and the two don't mix. Even if we would ignore that, there is the matter that Jackson is a 3rd party library, which is not under our control.

In short, if you want to customise the way the MappingJackson2HttpMessageConverter reads JSON, then please configure Jackson to do so, by referring to the Jackson documentation, or potentially filing an issue if Jackson does not provide the functionality you require.