Autowired gives Null value in Custom Constraint validator

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:

  1. Your objects will be validated by the library of your choice
  2. Your custom validators will be able to use Spring's functionality while having validation to be executed by Hibernate.

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;
}

You can fix this with two aproaches:

  • Try to inject Services on your validator using Spring.

  • Initialize it manually overriding Validator's initialize method.

I had the same problem time ago and finally i decided to use second option avoiding tons of problems.

As you point you must define one initialize method on your validator and there you can use a ServiceUtils to get the service bean you need:

@Autowired
private EmployeeService employeeService;

@Override
public void initialize(EmployeeValidation constraintAnnotation) {
  //Use an utility service to get Spring beans
  employeeService = ServiceUtils.getEmployeeService();
}

And ServiceUtils is a normal Spring bean with a static reference to itself used in the static methods.

@Component
public class ServiceUtils {
  private static ServiceUtils instance;

  @Autowired
  private EmployeeService employeeService;

  /* Post constructor */

  @PostConstruct
  public void fillInstance() {
    instance = this;
  }

  /*static methods */

  public static EmployeeService getEmployeeService) {
    return instance.employeeService;
  }
}

So you are using Spring to inject the services you need but not in the usual way. Hope this helps.


In your bean definition

@Bean
public Validator validator() {
    return new LocalValidatorFactoryBean().getValidator();
}

What's the type of Validator in the method definition? You should make sure it returns javax.validation.Validator, not Validator from Spring.

Letting Spring bootstrap the validator will it also cause to pass a SpringConstraintValidatorFactory to Hibernate Validator which will enable dependency injection within constraint validators.