When I use BindingResult
with @Validated
annotation in a method, validation is not working. If I remove BindingResult
from the method parameters, it works fine. I used @ControllerAdvice
.
Any idea why is it not working?
My code is below:
public ResponseEntity<?> dologin(
@Validated({ Group.Login.class }) @RequestBody User user,
BindingResult errors)
{
// somecode
}
As per the Validation, Data Binding, and Type Conversion documentation,
any validation message will be automatically added to the binder’s BindingResult
.
There will be no impact if I remove it, right?
Since you only provided the code from your controller method, I'm adding some additional information that is needed in order to get validation working in a Spring 4 application, so you can see where any differences might be. I am minimally assuming the following:
@RequestMapping(method = RequestMethod.POST)
public String dologin(@Valid @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
@RequestMapping(method = RequestMethod.POST)
public String dologin(@Validated @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
or, if using validation groups:
@RequestMapping(method = RequestMethod.POST)
public String dologin(@Validated({ User.Login.class }) @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
@NotBlank(message = "{firstName.required}")
@Size(min = 2, max = 24, message = "{firstName.size}")
@Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}")
private String firstName;
or, if using validation groups:
public interface Login extends Default {}
@NotBlank(message = "{firstName.required}", groups = {Login.class})
@Size(min = 2, max = 24, message = "{firstName.size}", groups = {Login.class})
@Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}", groups = {Login.class})
private String firstName;
src/main/resources
:firstName.required=First name is required.
firstName.size=First name must be between {min} and {max} characters long.
firstName.format=First name may contain only letters, apostrophes, spaces and hyphens.
Make sure your Bean Validation specification version matches your implementation version. Bean Validation API 2.0 was released in August 2017. The Bean Validation 2.0 Reference Implementation is Hibernate Validation Engine 6.0.
The validation errors will be added to the BindingResult
if that is present in the method parameters. Alternatively, you can use Errors
in place of BindingResult
- the API is essentially the same. Both of these work equivalently in my above implementation.
However, if I leave the parameter out of my controller method, I see (from logging) that the validation is triggered and the appropriate errors are raised and the mapping of my message keys to their properties succeed, but my Server Error page is rendered instead of my expected view. For additional information on the requirement of this parameter, see this related question on the BindingResult/Errors parameter.
Aug 31, 2017 2:21:56 PM com.test.spring.controller.ErrorController handleException
SEVERE: Server Error
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'userForm' on field 'firstName': rejected value []; codes [Size.userForm.firstName,Size.firstName,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName],24,2]; default message [First name must be between 2 and 24 characters long.]
Field error in object 'userForm' on field 'firstName': rejected value []; codes [NotBlank.userForm.firstName,NotBlank.firstName,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName]]; default message [First name is required.]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:117)
I see very consistent behavior in all of the above combinations.
One difference I note is that you are using @ControllerAdvice
in your example. Most of my controllers use the @Controller
annotation (local controller errors), not @ControllerAdvice
(used for global errors, such as for rendering HTTP 404 or 500 error pages). See this related question/answer for the use of @ControllerAdvice
.
In the above error log, you see that ErrorController
is the one reporting the validation errors if I leave out the BindingResult
/Errors
parameter, and indeed that is my controller class that uses @ControllerAdvice
annotation instead of @Controller
. By using @ControllerAdvice
on your login controller you may be interfering with normal error handling.
Since you are using the Hibernate-specific @Validated
group validation annotation instead of the JSR-303/349/380 specification @Valid
annotation, there may be some differences between the implementation you used (I'm guessing version 5, which conformed to API 1.1). I am using version 6.0.2, which conforms to the new (August 2017) Bean Validation Framework API 2.0.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With