Reputation: 7630
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?
Upvotes: 5
Views: 12841
Reputation: 169
In my case:
use @Valid
annotation from Jakarta package
instead of javax package
.
spring-boot version: '3.0.6'
Upvotes: 0
Reputation: 622
Hibernate Validator 6 does not work out of the box with Spring 4 because Spring 4's LocalValidatorFactoryBean does not yet use Java's Service Provider mechanism to discover the Validator implementation, so you need to create the validator yourself specifying the implementation.
When using @EnableWebMvc
:
@Bean
public javax.validation.Validator localValidatorFactoryBean() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setProviderClass("org.hibernate.validator.HibernateValidator");
return bean;
}
Or in XML:
<mvc:annotation-driven validator="validator-adapter"/>
<bean id="validator-adapter"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass"
value="org.hibernate.validator.HibernateValidator" />
</bean>
Upvotes: 1
Reputation: 7494
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.
Upvotes: 6