BindException thrown instead of MethodArgumentNotValidException in REST application

可紊 提交于 2021-02-17 21:44:50

问题


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.


回答1:


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



来源:https://stackoverflow.com/questions/23211076/bindexception-thrown-instead-of-methodargumentnotvalidexception-in-rest-applicat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!