Reputation: 5731
How validate incoming arguments with Hibernate ?
In XML
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="validator" ref="validator"/>
</bean>
In Java
@Validated
public class UserService
@Override
@NotNull
public User registerUser(@NotEmpty String name, String username, String password, boolean google, boolean facebook)
This approach not work i call method with error params and validation not work.
Upvotes: 4
Views: 12082
Reputation: 197
For current version you don't have to add all beans that "asinkxcoswt" wrote in https://stackoverflow.com/a/23384229/6028739.
To your pom.xml add this:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.4.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
Add this line to your application context:
<bean id="validationFactory" class="javax.validation.Validation"
factory-method="buildDefaultValidatorFactory" />
All entities annotated with @Validated are now validated and throw javax.validation.ConstraintViolationException
with list of constraint violations with details e.g.
javax.validation.ConstraintViolationException: Validation failed for classes [com.example.Class] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must be greater than or equal to 0', propertyPath=amount, rootBeanClass=class com.example.Class, messageTemplate='{javax.validation.constraints.Min.message}'}
]
Upvotes: 0
Reputation: 2554
Question Clarification
When using Hibernate Validator (HV) 4.2 with Spring-MVC 4, e.g. with dependencies:
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
compile 'org.springframework:spring-webmvc:4.0.3.RELEASE'
compile 'org.hibernate:hibernate-validator:4.2.0.Final'
runtime 'javax.servlet:jstl:1.1.2'
}
one can tell Spring to automatically use HV to validate method calls of classes annotated with @Validated
(as in asker's example) by declaring following beans in the configuration file,
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
When the target's method get called and has somethings that violates its constraints, the MethodConstraintViolationException
is thrown. For example, something like this will be raised if one happeded to call UserService#registerUser(...)
, passing an empty String to where annotated with @NotEmpty
... The following constraint violations occurred: [MethodConstraintViolationImpl
[method=public abstract void foo.UserService.registerUser(java.lang.String),
parameterIndex=0, parameterName=arg0, kind=PARAMETER, message=may not be empty,
messageTemplate={org.hibernate.validator.constraints.NotEmpty.message}, ...
But the problem is if you change the dependencies from above to
dependecies {
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
compile 'org.springframework:spring-webmvc:4.0.3.RELEASE'
compile 'org.hibernate:hibernate-validator:5.1.0.Final' //**note the change here**
runtime 'javax.servlet:jstl:1.1.2'
}
then you will get an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'org.springframework.validation.beanvalidation.MethodValidationPostProcessor#0'
defined in class path resource [spring/config/web/main-config.xml]: Invocation of init
method failed; nested exception is javax.validation.ValidationException: Unable to
instantiate Configuration.
Solution
Add 2 additional dependecies to the classpath as follows,
dependecies {
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
providedCompile 'javax.el:el-api:2.2'
providedCompile 'org.glassfish.web:el-impl:2.2'
compile 'org.springframework:spring-webmvc:4.0.3.RELEASE'
compile 'org.hibernate:hibernate-validator:5.1.0.Final' //**note the change here**
runtime 'javax.servlet:jstl:1.1.2'
}
And the validation will comeback to life. But this time, instead of MethodConstraintViolationException
, it raises ConstranitViolationException
with no details of what has been violated.
I am not sure how Spring manage this internally and wheter you can unfold the violation details out of this Exception. HV 5 no longer supports MethodConstraintViolationException
and its relatives, e.g. MethodValidator
, MethodConstraintViolation
. This is something to do with Bean Validation 1.1 specification, which has some changes in method-level validation from BV 1.0. I suggest creating the validation service yourself using aspect and with ExecutableValidator
(instead of the old MethodValidator
) as explained in HV's Reference guide.
Note that you if you try to obtain the validator like this,
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
ExecutableValidator executableValidator = factory.getValidator().forExecutables();
you may get ValidationException: Unable to instantiate configuration.
I can solve this problem by do this
ValidatorFactory factory = Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
ExecutableValidator executableValidator = factory.getValidator().forExecutables();
Upvotes: 6
Reputation: 1
Apparently Spring suggests not to use ExecutableValidator but MethodValidationInterceptor instead, see javadoc: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html
Upvotes: 0
Reputation: 807
I include the following in addition to spring and other project dependencies in the maven pom file.
<properties>
<hibernate.version>4.3.1.Final</hibernate.version>
<hibernate.validator.version>5.1.0.Final</hibernate.validator.version>
<javax.el.version>3.0.0</javax.el.version>
<asm.version>3.3.1</asm.version>
</properties>
<dependencies>
<!-- Hibernate et al-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator.version}</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>${javax.el.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>${javax.el.version}</version>
</dependency>
<!-- asm allows hibernate validator to retrieve method parameter names when reporting method validation
without this you just get arg0 instead of argument name -->
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>${asm.version}</version>
</dependency>
</dependencies>
In my java config for spring I set
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("validation");
messageSource.setCacheSeconds(1);
return messageSource;
}
@Bean
LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
validator.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
return validator;
}
@Bean
@Autowired
MethodValidationPostProcessor getValidationPostProcessor(LocalValidatorFactoryBean validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator);
return processor;
}
LocalVariableTableParameterNameDiscoverer works with ASM to give proper parameter names in the ConstraintViolationException that will be thrown when validation fails.
Upvotes: 4