Null request body not getting caught by Spring @Re

2019-04-21 12:46发布

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?

3条回答
smile是对你的礼貌
2楼-- · 2019-04-21 13:29

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!

查看更多
成全新的幸福
3楼-- · 2019-04-21 13:33

According to the JSON specification, null is a valid value. Jackson, which Spring uses behind the scenes, deserializes a null JSON value to a Java null reference.

You'll have to do what you described and check for it in your controller. Alternatively, you can create your own HandlerMethodArgumentResolver to do that for you.

查看更多
可以哭但决不认输i
4楼-- · 2019-04-21 13:39

Let's put it this way: If an object doesn't exist, then it can't be invalid.

@Valid only causes Spring to check if the item object complies with some rules. It doesn't check if it's there. If the request body is empty or an empty object then the process stops before validation. For in the default setup of Spring and Jackson those two cases are not allowed.

So you can either check for null or write an extension, as @Sotirios Delimanolis has pointed out.

查看更多
登录 后发表回答