simonl
simonl

Reputation: 1240

How to create a dependent Guice (Play / Scala) binding?

I am using Scala + Play and the out of box Guice set up for dependency injection. I am also using Akka Persistence behind the scenes and would like to create a binding for a custom read journal that I can then inject around my application.

Unfortunately, the read journal constructor (which I do not control) requires an explicit reference to the actor system:

PersistenceQuery(actorSystem).readJournalFor[CustomReadJournal]("custom-key")

How do I get a reference to the underlying actorSystem from within a binding definition class (Module)? Is this possible? More generally, is it possible to define interdependent bindings (a la Scaldi?)

My Module class entry currently looks like:

bind(classOf[CustomReadJournal]).toInstance(PersistenceQuery(<what do i put here?>).readJournalFor[CustomReadJournal]("custom-journal"))

Thanks in advance for the help!

Upvotes: 0

Views: 731

Answers (1)

EdgeCaseBerg
EdgeCaseBerg

Reputation: 2841

If you need to do some kind of logic to create a dependency injection it is useful to use the @Provides annotation. For example:

trait MyProvider {
  @Provides
  def provideThing(): Thing = {
    //make the thing and return it
  }
}
class MyModule extends AbstractModule with MyProvider {
   override def configure() {
     bind(classOf[TraitYYY]).to(classOf[ClassThatTakesThingAsParameter])
   }
}

A useful thing to know is that @Provides methods can themselves take parameters and get their arguments injected. For example:

@Provides
def provideThingNeedingParameter(param: P): ThingNeedingParam = {
   new ThingNeedingParam(param)
}

Which is relevant to your situation I believe since you want to provide an actor system to an instance of some class.

// You can use @Singleton with @Provides if you need this to be one as well!
@Provides
def provideActorSystem(app: Application): ActorSystem = {
    play.api.libs.concurrent.Akka.system(app)
}

@Provides
def providePersistenceQuery(actorSystem: ActorSystem): PersistenceQuery = {
    PersistenceQuery(actorSystem)
}

@Provides 
def provideCustomReadJournal(persistenceQuery: PersistenceQuery):CustomReadJournal = {
    persistenceQuery.readJournalFor[CustomReadJournal]("custom-key")    
}

By creating an @Provides annotated method for your CustomReadJournal you can avoid the bind call from configure entirely and control the parameters a bit more. Also, if you need to, @Provides works with @Singleton. I haven't used Akka persistence, but I think this should help you

Upvotes: 2

Related Questions