1

According to documentation for Play 2.6:

The deprecated static methods play.libs.Akka.system and play.api.libs.concurrent.Akka.system were removed. Use dependency injection to get an instance of ActorSystem and access to the actor system.

The doc provides an example using annotation for POJO's, however the syntax doesn't seem to work when used within a Module...

Our Class def looks like so:

public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {...}

1) Attempting to use @Inject on a class member yields a NULL reference:

    @Inject
    protected ActorSystem system;

2) Attempting to use @Inject on the module's constructor throws play.api.PlayException: No valid constructors :

    public SomeMagicalModule (@Inject AkkaSystem system) {...}

Is there another avenue to get the AkkaSystem, or are we missing something simple?

TIA.

Rich Dougherty
  • 3,231
  • 21
  • 24
mjk
  • 659
  • 1
  • 9
  • 20

2 Answers2

2

You can use @Provides

When you need code to create an object, use an @Provides method. The method must be defined within a module, and it must have an @Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method. If the @Provides method has a binding annotation like @PayPal or @Named("Checkout"), Guice binds the annotated type. Dependencies can be passed in as parameters to the method. The injector will exercise the bindings for each of these before invoking the method.

@Provides
CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
  PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
  processor.setApiKey(apiKey);
  return processor;
}

However, you should take into account that

Whenever the injector needs an instance of that type, it will invoke the method

So, if you have two components that depend on a Provided component, in this case the CreditCardProcessor, you'll end up with 2 instances of this component because the Guice injector invokes the method each time it needs to inject an instance of this type.

Scopes provide a solution to this, you have to add the @Singleton annotation.

@Provides
@Singleton
CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
  PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
  processor.setApiKey(apiKey);
  return processor;
}

In your case it will be

public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {

  @Provides
  @Singleton
  @Named("some-actor")
  ActorRef createActor(system: ActorSystem){
    system.actorOf(...)
  }
}

Credits to codejanovic, see his answer.

Anyway, if you want the reference to the ActorSystem to create Actors, you should use AkkaGuiceSupport (I see that you are already adding it to your module but you don't seem to use it).

gabrielgiussi
  • 9,245
  • 7
  • 41
  • 71
  • Great detail - thanks. I've flagged this as the "answer" to the post since it strikes at the heart of the matter: how to access Play's ActorSystem within a Module. – mjk Dec 03 '17 at 21:33
0

Modules can't actually have @Inject annotations. You use modules to configure how injection will work, but you can't inject things into them. The reason is that Play/Guice first create and configure all the modules and then do the injection. The injection isn't avaiable until the configuration is finished.

Guice documentation about modules: https://github.com/google/guice/wiki/Bindings#creating-bindings

You can get an ActorSystem in one of the objects that created by Guice, e.g. a controller:

public class MyController {
  @Inject // <--- goes before constructor not on parameter
  public MyController(ActorSystem actorSystem) { ... }
  ...
}

Guice documentation about @Inject: https://github.com/google/guice/wiki/Injections#injections

Rich Dougherty
  • 3,231
  • 21
  • 24
  • Thanks for the insight, Rich. We finally got tired of trying and simply threw the code into a spawned Actor bound within that Module. Not really what we wanting, but it'll do to the time being. – mjk Nov 30 '17 at 15:29