1

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?
Alexander Stohr
  • 159
  • 1
  • 18
msmith
  • 43
  • 5

1 Answers1

2

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);
}
vsbehere
  • 666
  • 1
  • 7
  • 23
  • Thanks for your answer. I've seen this code before, but I don't now where to put `Injector injector = Guice.createInjector(...your modules...);` in my code. additionaly: I don't have any modules yet. The only module I have was generated by the ninja archetype (conf/Module.java) and is currently empty. – msmith May 04 '17 at 12:07
  • does your project contains web.xml? if yes, you can create GuiceServletContextListener to create an injector. – vsbehere May 04 '17 at 12:32
  • 1
    I ended up creating a ninja start action `@Start(order = 91) public void configureInjector() { InjectorProvider.INSTANCE.setInjector(injector); }`. Now everything works fine. Thank you for your input. – msmith May 05 '17 at 07:23