BindException instead of MethodArgumentNotValidException in a REST application

I have a simple w760> control controller with some verification. My understanding is that validation errors will throw a MethodArgumentNotValidException. However, my code instead throws a BindException. In debugging messages, I also see that the application returns a null ModelAndView.

Why should the break manager throw a BindException or return a null ModelAndView?

Note. I am testing my web application using curl and creating an HTTP POST

curl -X POST http://localhost:8080/tasks 

I intentionally omit the "name" parameter, which is a required field marked with @NotNull and @NotBlank annotations.

My controller:

 @RestController public class TasksController { private static Logger logger = Logger.getLogger(TasksController.class); @Autowired private MessageSource messageSource; @Autowired private Validator validator; @InitBinder protected void initBinder(WebDataBinder binder){ binder.setValidator(this.validator); } @RequestMapping(value = "/tasks", method = RequestMethod.POST) public Task createTask(@Valid TasksCommand tasksCommand){ Task task = new Task(); task.setName(tasksCommand.getName()); task.setDue(tasksCommand.getDue()); task.setCategory(tasksCommand.getCategory()); return task; } } 

My class is "command" (containing validation annotations)

 public class TasksCommand { @NotBlank @NotNull private String name; private Calendar due; private String category; ... getters & setters ommitted ... } 

My RestErrorHandler class:

 @ControllerAdvice public class RestErrorHandler { private static Logger logger = Logger.getLogger(RestErrorHandler.class); @Autowired private MessageSource messageSource; @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public ErrorsList processErrors(MethodArgumentNotValidException ex){ logger.info("error handler invoked ..."); BindingResult result = ex.getBindingResult(); List<FieldError> fieldErrorList = result.getFieldErrors(); ErrorsList errorsList = new ErrorsList(); for(FieldError fieldError: fieldErrorList){ Locale currentLocale = LocaleContextHolder.getLocale(); String errorMessage = messageSource.getMessage(fieldError, currentLocale); logger.info("adding error message - " + errorMessage + " - to errorsList"); errorsList.addFieldError(fieldError.getField(), errorMessage); } return errorsList; } } 

The processErrors method, marked with the @ExceptionHandler (...) annotation, is never called. If I try to catch a BindException using the @ExceptionHandler (...) annotation, this handler method is actually called.

I have a couple of support classes - Task, TaskCommand, Error and ErrorsList - I can send the code if necessary.

+7
java spring rest
source share
1 answer

The problem was my curl command.

curl -d sends the Content-Type "application / x-www-form-urlencoded". As a result, Spring interprets the data as web form data (instead of JSON). Spring uses FormHttpMessageConverter to convert the POST body to a domain object and throws a BindException.

We want Spring to treat POST data as JSON and use MappingJackson2HttpMessageConverter to parse the POST body into an object. This can be done by specifying the "Content-Type" header with the curl command:

 curl -X POST -H "Content-Type: application/json" -d '{"name":"name1", "due":"2014-DEC-31 01:00:00 PDT", "category":"demo"}' http://localhost:8080/tasks 

See this post on how to publish JSON data using curl: How to send JSON POST data using Curl from a terminal / command line to test Spring REST?

Also, here's the relevant Spring documentation on MessageConverters: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestbody http: //docs.spring .io / spring / docs / current / spring-framework-reference / html / remoting.html # rest-message-conversion

+2
source share

All Articles