Search code examples
javadependency-injectionguiceninjaframework

How to use Dependency Injection in a ConstraintValidator in Ninjaframework?


I'm having problems to validate a POST request with ninja framework (6.0.0-rc1) and a custom ConstraintValidator.

Here is my current implementation:



    @Singleton
    public class GameController {
        public Result postGame(@JSR303Validation final GameRequestObject gameRequestObject, final Validation validation) {

            if(validation.hasViolations()){ 
                return Results.json().render(validation.getViolations());
            }

            //... code to save game to DB etc ...
            return Results.ok();
        }
    }
    
    
    public class GameRequestObject {

        @ValidPlayerId // - Custom validation constraint
        private long playerId;

        //... getter, setter etc ...    
    }
    
    @Target( { METHOD, FIELD, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    @Constraint(validatedBy = PlayerIdValidator.class)
    public @interface @ValidPlayerId {

        String message() default "{ch.some.label.here}";
        Class[] groups() default {};
        Class[] payload() default {};

    }
    
    public class PlayerIdValidator implements ConstraintValidator {

        @Inject // - Does not work
        private PlayerDao playerDao; // - Is always null

        public void initialize(ValidPlayerId validPlayerId) {} 

        public boolean isValid(Long value, ConstraintValidatorContext context) {
            return playerDao != null && playerDao.isPlayerIdValid(value);
        }

    }


The problem is, that the playerDao is not injected at all. I narrowed the problem. It seems that the default constructor is called instead of using Dependency Injection. According to this post this could be changed by using a custom ConstraintValidatorFactory.

Now I have the following two issues:

  1. Even with the provided link to the hibernate documentation I don't know how to implement such a factory such that the DI is working.
  2. Where do I register / bind / ("whatever") my factory in the ninja framework?

Solution

  • As your PlayerIdValidator is not instantiated using guice, you won't be able to enable dependency injection in that class. You can use alternate solution of using injector.

    To store your injector reference you could use a Singleton - here I implement it by using an enum:

    public enum InjectorProvider {
      INSTANCE;
      private Injector injector;
      public Injector getInjector() {
        return injector;
      }
      public void setInjector(Injector injector) {
        this.injector = injector;
      }      
    }
    

    I do not know how you initialize guice, but you probably have some code like this, so add the code to store the injector:

    Injector injector = Guice.createInjector(...your modules...);
    InjectorProvider.INSTANCE.setInjector(injector);
    

    Now use this provider to get injector and instantiate PlayerDao:

    public boolean isValid(Long value, ConstraintValidatorContext context) {
        Injector injector = InjectorProvider.INSTANCE.getInjector();
        PlayerDao playerDao = injector.getInstance(PlayerDao.class);
        return playerDao != null && playerDao.isPlayerIdValid(value);
    }