4

Play 2.4 supports dependency injected controllers out of the box. I have successfully used constructor injection to provide dependencies to my controllers. However, when using action composition, fields marked with @Inject are not injected.

Is there any way to inject dependencies into a composite action?

Example code for controller:

public class Application extends Controller {
    private DomainService ds;

    @Inject
    public Application(DomainService ds) {
        this.ds = ds;
    }

    @Security.Authenticated(RandomAuthenticator.class)
    public Result index() {
        return ok();
    }

}

Example code for composite action:

public class RandomAuthenticator extends Security.Authenticator {
    @Inject private RandomService rs; // This field is never injected

    @Override
    public String getUsername(Context context) {
        float randFloat = rs.nextFloat(); // Error! rs is always null

        if (randFloat > 0.1) {
            return "foo";
        }

        return null;
    }
}
cyang
  • 5,574
  • 2
  • 25
  • 34
  • Possibly related solution, but in Scala: http://stackoverflow.com/questions/31098911/ – cyang Jul 08 '15 at 21:35
  • This issue was fixed in Play 2.4.3 https://github.com/playframework/playframework/issues/2188 – cyang Feb 16 '16 at 21:44

2 Answers2

0

Instead of field injection you could try using the class' constructor to inject with Guice:

public class RandomAuthenticator extends Security.Authenticator {

    private RandomService rs;   

    @Inject
    RandomAuthenticator(RandomService randomService) {
        this.rs = randomService;
    }

    @Override
    public String getUsername(Context context) {
        float randFloat = rs.nextFloat(); // Error! rs is always null

        if (randFloat > 0.1) {
            return "foo";
        }

        return null;
    }
}
Kris
  • 4,595
  • 7
  • 32
  • 50
  • Unfortunately this causes an `java.lang.NoSuchMethodException: auth.RandomAuthenticator.()` as play framework attempts to instantiate the Authenticator with using a parameterless constructor ([source](https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/java/play/mvc/Security.java#L36)) – cyang Jul 09 '15 at 17:18
0
public class RandomAuthenticator extends Security.Authenticator {

    private final RandomService rs;   

    public RandomAuthenticator(RandomService randomService) {
        this.rs = randomService;
    }

    ...
}

Then use an @Provides method in your Guice module:

@Provides
RandomAuthenticator provideRandomAuthenticator(RandomService randomService) {
    return new RandomAuthenticator(randomService);
}
David
  • 5,184
  • 3
  • 41
  • 67
  • I believe this, as well as the code in the question, will work in recent versions of Play (≥2.4.3) because of a bugfix: https://github.com/playframework/playframework/commit/0ca04ba0c830a4842bff55a6512a1cff9baa7384 – cyang Feb 16 '16 at 21:48