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 SpringHttpMessageConverter
abstraction. Specifically, you are using theMappingJackson2HttpMessageConverter
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.