BindException thrown instead of MethodArgumentNotValidException in REST application

exceptionhandler, java, rest, spring

Solution

The problem was with 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 body of POST into domain object and results in a BindException.

What we want is for Spring to treat POST data as JSON and use the MappingJackson2HttpMessageConverter to parse body of POST into object. This can be done by specifying the "Content-Type" header with 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 for how to post JSON data using curl: How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?

Also, here's the relevant Spring documentation about 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

Problem

I have a simple Spring Rest Controller with some validation. My understanding is that validation failures would throw a MethodArgumentNotValidException. However, my code throws a BindException instead. In debug messages, I also see the app returning a null ModelAndView. Why would a Rest Controller throw BindException or return a null ModelAndView? Note: I am testing my web application using curl and making an HTTP POST ``` curl -X POST http://localhost:8080/tasks ``` I am intentionally omitting 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 "command" class (that contains 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 @ExceptionHandler(...) annotation never gets called. If I try to catch a BindException using @ExceptionHandler(...) annotation, that handler method does get invoked. I have couple of support classes - Task, TaskCommand, Error and ErrorsList - that I can post code for if needed.

Original source

Related problems