1

I have tried several methods to inject dependency into my ConstraintValidator implementation but nothing is working. I have tried almost all stackoverflow threads. I am using Hibernate Validator to achieve custom validation. I want FileService to be injected into ApiMockResponseValidator. I am sharing the things that I have tried.

  1. Simple @Autowired annotation and constructor injection:
@Component
public class ApiMockResponseValidator
    implements ConstraintValidator<MockResponse, ApiMockResponse> {

  @Autowired
  FileService fileService;

  private boolean validate(....) {
     // logic
  }

  @Override
  public boolean isValid(ApiMockResponse mockResponse, ConstraintValidatorContext context) {
    System.out.println("\n\n  --- " + fileService + " --- \n\n");  // remains null
    // validate()
  }
}

I have tried this by Constructor injection only and also by removing @Component but nothing works and the Validator is not instantiating. Simple @Autowired is not injecting dependency and constructor autowiring is giving

Caused by: javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: com.lendin.ib.utils.validator.ApiMockResponseValidator.
    at org.hibernate.validator.internal.util.privilegedactions.NewInstance.run(NewInstance.java:44)
...
...
Caused by: java.lang.NoSuchMethodException: com.test.ApiMockResponseValidator.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
  1. Creating Validator bean
@Configuration
public class ValidatorConfig {


  @Bean
  @Autowired
  public Validator validator(AutowireCapableBeanFactory autowireCapableBeanFactory) {

    ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()
        .constraintValidatorFactory(
            new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
        .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    return validator;
  }
}

Even after this fileService is null.

  1. Tried creating LocalValidatorFactoryBean
@Configuration
public class ValidatorConfig {

  @Bean
  @Primary
  @Autowired
  public Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {
    new SpringConstraintValidatorFactory(autowireCapableBeanFactory);
    LocalValidatorFactoryBean x = new LocalValidatorFactoryBean();
    x.setConstraintValidatorFactory(
        new SpringConstraintValidatorFactory(autowireCapableBeanFactory));
    return x;
  }

}

This is also not helping and fileService is null.

Is there any way I can achieve injecting dependency?

I know that if SpringConstraintValidatorFactory can instantiate ConstraintValidator implementation and Hibernate can just use it rather then instantiating the implementation itself then it can work.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • You do have a `FileService` Bean, don't you? Did you declare it in a `@Configuration`? Then you could use constructor injection and try to create the validator in the same config with `return new ApiMockResponseValidator(fileService())`. – daniu Jul 07 '22 at 12:04

2 Answers2

0

In the case that the ConstraintValidator instance is created outside of Spring scope (maybe Hibernate does that), the dependency injection is not managed by Spring.

What you can do as a workaround, is create a FileServiceHolder as a singleton

class FileServiceHolder {
   private static final FileServiceHolder INSTANCE = new FileServiceHolder();
   private FileService fileService;

   private FileServiceHolder() {
   }

   public static FileServiceHolder getInstance() {
      return INSTANCE;
   }

   @Autowired
   public setFileService(FileService fileService) {
      this.fileService = fileService;
   }
}

And in a Configuration class create a bean from that singleton

@Configuration
class AppConfig {
   @Bean
   FileServiceHolder fileServiceHolder() {
      return FileServiceHolder.getInstance();
   }
}

Exposing the same object (singleton) as a bean, makes it possible for Spring to inject the dependencies. This is done through the setter method setFileService.

Now in your Validator class, you can access the FileService through the FileServiceHolder

class Validator {
   boolean validate(....) {
      FileServiceHolder.getInstance().doStuff();
   }
}
Ahmed Sayed
  • 1,429
  • 12
  • 12
-1

I had the same problem and it was solved adding this in application.properties :

spring.jpa.properties.javax.persistence.validation.mode=none

Found the solution here

J. Sabatier
  • 305
  • 2
  • 10