I am currently running into an issue with the @RequestBody
annotation in Spring. I currently have all my validation annotations set up on my models properly, and they work great when an object is POSTed. Everything works as expected even when the request body posted is completely empty or an empty object "{}". The problem arises when someone tries to post a request body of "null". This somehow gets through the @Valid
annotation and is not caught, causing a NullPointerException
when I try to access the object. I have pasted a snippet of my controller below.
@Secured({ ROLE_ADMIN })
@RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE } )
public HttpEntity<Resource<Item>> addItem(@RequestBody @Valid Item item) throws Exception {
Resource<Item> itemResource = this.itemResourceAssembler.toResource(this.itemService.save(item));
return new ResponseEntity<Resource<Item>>(itemResource, HttpStatus.CREATED);
}
I do some checks in itemService.save()
to see if an item exists in the database already, since this is being used as an upsert. When I access the item passed to save I get the NullPointerException
because item is null. I've tried using the "required" parameter of @RequestBody
but that only checks to see if there was something POSTed. As stated above, the null item is only passed through when a user posts "null" without the quotes as the request body. Is there a automated Spring annotation or configuration to stop this null from being passed through, or should I just put if(item == null) throw new Exception();
in all of my controllers where this could crop up?
body. The read-only body property of the Request interface contains a ReadableStream with the body contents that have been added to the request. Note that a request using the GET or HEAD method cannot have a body and null is return in these cases.
Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object. Spring automatically deserializes the JSON into a Java type, assuming an appropriate one is specified.
HTTP's GET method does not include a request body as part of the spec. Spring MVC respects the HTTP specs. Specifically, servers are allowed to discard the body.
By the looks of the code snippet you posted, you have a clearly defined service layer. I would suggest using method level validation in you service as follows
@Validated
public interface ItemService {
public Item save(@NotNull Item item);
If your using spring's XML config add this to your app's context xml.
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
a MethodConstraintViolationException will be thrown that could be caught in a @ControllerAdvice if you have that defined.
@ExceptionHandler(MethodConstraintViolationException.class)
Happy Coding!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With