Spring Boot binding and validation error handling in REST controller
Usually when Spring MVC fails to read the http messages (e.g. request body), it will throw an instance of HttpMessageNotReadableException
exception. So, if spring could not bind to your model, it should throw that exception. Also, if you do NOT define a BindingResult
after each to-be-validated model in your method parameters, in case of a validation error, spring will throw a MethodArgumentNotValidException
exception. With all this, you can create ControllerAdvice
that catches these two exceptions and handles them in your desirable way.
@ControllerAdvice(annotations = {RestController.class})public class UncaughtExceptionsControllerAdvice { @ExceptionHandler({MethodArgumentNotValidException.class, HttpMessageNotReadableException.class}) public ResponseEntity handleBindingErrors(Exception ex) { // do whatever you want with the exceptions }}
This is the code what i have used in one of my project for validating REST api in spring boot,this is not same as you demanded,but is identical.. check if this helps
@RequestMapping(value = "/person/{id}",method = RequestMethod.PUT)@ResponseBodypublic Object updatePerson(@PathVariable Long id,@Valid Person p,BindingResult bindingResult){ if (bindingResult.hasErrors()) { List<FieldError> errors = bindingResult.getFieldErrors(); List<String> message = new ArrayList<>(); error.setCode(-2); for (FieldError e : errors){ message.add("@" + e.getField().toUpperCase() + ":" + e.getDefaultMessage()); } error.setMessage("Update Failed"); error.setCause(message.toString()); return error; } else { Person person = personRepository.findOne(id); person = p; personRepository.save(person); success.setMessage("Updated Successfully"); success.setCode(2); return success; }
Success.java
public class Success {int code;String message;public int getCode() { return code;}public void setCode(int code) { this.code = code;}public String getMessage() { return message;}public void setMessage(String message) { this.message = message;}}
Error.java
public class Error {int code;String message;String cause;public int getCode() { return code;}public void setCode(int code) { this.code = code;}public String getMessage() { return message;}public void setMessage(String message) { this.message = message;}public String getCause() { return cause;}public void setCause(String cause) { this.cause = cause;}}
You can also have a look here : Spring REST Validation
You can't get BindException with @RequestBody. Not in the controller with an Errors
method parameter as documented here:
Errors, BindingResult For access to errors from validation and data binding for a command object (that is, a @ModelAttribute argument) or errors from the validation of a @RequestBody or @RequestPart arguments. You must declare an Errors, or BindingResult argument immediately after the validated method argument.
It states that for @ModelAttribute
you get binding AND validation errors and for your @RequestBody
you get validation errors only.
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-methods
And it was discussed here:
For me it still does not make sense from a user point of view. It is often very important to get the BindExceptions to show the user a proper error message. The argument is, you should do client side validation anyway. But this is not true if a developer is using the API directly.
And imagine your client side validation is based on an API request. You want to check if a given date is valid based on a saved calendar. You send the date and time to the backend and it just fails.
You can modify the exception you get with an ExceptionHAndler reacting on HttpMessageNotReadableException, but with this exception I do not have proper access to which field was throwing the error as with a BindException. I need to parse the exception message to get access to it.
So I do not see any solution, which is kind of bad because with @ModelAttribute
it is so easy to get binding AND validation errors.