I am totally new to Spring and I have looked in to a few answers on SO for the asked problem. Here are the links:
Spring 3.1 Autowiring does not work inside custom constraint validator
Autowiring a service into a validator
Autowired Repository is Null in Custom Constraint Validator
I have a Spring project in which I want to use Hibernate Validator for an object validation. Based on what I read online and a few forums I tried to inject validator as follows:
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
But wherever I was using
@Autowired
Validator validator;
It was taking Spring's validator implementation instead of the Hibernate's validator. I couldn't figure out how to exactly inject Hibernate validator and simply Autowire it across other classes so I used a cheap trick, now my Java Config looks like this
@Bean
public Validator validator() {
// ValidatorImpl is Hibernate's implementation of the Validator
return new ValidatorImpl();
}
(I would really appreciate if someone can actually point me into the right direction on how to avoid getting Hibernate Validator in this Hacky way)
But lets come to the main issue here:
Here is custom validation definition
@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = EmployeeValidator.class)
@Documented
public @interface EmployeeValidation {
String message() default "{constraints.employeeConstraints}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}
My Custom Validator
public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {
@Autowired
private EmployeeService employeeService;
@Override
public void initialize(EmployeeValidation constraintAnnotation) {
//do Something
}
@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
return false;
}
}
In the above Custom Constraint Validator I get the employeeService null. I know that any implementations of ConstraintValidator are not instantiated when Spring is starting up but I thought adding the ValidatorImpl() will actually fix that. But it didn't.
Now I am stuck with a really hacky workaround and I do not want to continue with a code like that. Can someone please help me with my situation.
P.S. These are my imports in the Java Config file:
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
I hope the solution will help someone:
@Bean
public Validator validator () {
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
Initializing the validator with SpringConstraintValidatorFactory
so that injection works and providing the validator implementation to be Hibernate.class works in the following manner:
How it works:
Hibernate's ConstraintValidatorFactory
does not initialize any ConstraintValidators
unless they are called but SpringConstraintValidatorFactory
does by giving AutowireCapableBeanFactory
to it.
EDIT
As mentioned in one of the comments by @shabyasaschi To inject autowireCapableBeanFactory
you can change the method signature as:
Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {
or add getter and setter for it in the config file as follows:
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
return autowireCapableBeanFactory;
}
public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory) {
this.autowireCapableBeanFactory = autowireCapableBeanFactory;
}