Scala Guice - inject with a mixin - scala

Is it possible to instantiate the dependency first and then bind it in the module config method?
Currently I have the following config:
class PersonServiceImpl #Inject()(addressService: AddressService) {
...
}
class AppModule extends AbstractModule with ScalaModule {
def configure() {
bind[PersonService].to[PersonServiceImpl]
bind[AddressBook].to[AddressBookImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
... which works fine. What I want to do now is to move the instantiation of the AddressServiceImpl into a separate module. So, the problem is that in order to create an instance of AddressServiceImpl I need Guice to inject the addressBook parameter for me, but I also want to create the instance myself so I can mix SecureAddressView in:
class AddressModule extends AbstractModule with ScalaModule {
def configure() {
bind[AddressService].to[AddressServiceImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
This fails, though, as Guice comes back complaining about the provideAddressService method. It basically says that A binding to AddressService was already configured and points to the bind[AddressService].to[AddressServiceImpl] line in the configure method.
Any idea how to create an instance and mix in a trait while still delegating the resolution of downstream parameter dependencies to Guice?

OK, quite an obvious one but I was misled by the fact that I had to override the configure method. So, all I had to do is provide a dummy implementation for configure.
class AddressModule extends AbstractModule with ScalaModule {
override def configure(): Unit = ()
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
Although this still looks quite dodgy as I have to provide explicitly all the parameters to the AddressService constructor. There must be a more elegant way of mixin traits. Or maybe not...

Related

Creating a AbstractModule to inject a dependency for a 3rd party library

I have a 3rd party library that I am trying to inject the configuration into the constructor.
This is what I need to do:
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
bind(classOf[TwitterApi])
.to(classOf[MyTwitterApi])
.asEagerSingleton
}
}
The constructor of MyTwitterApi doesn't take a Play.api.Configuration but a typesafe.config.Config
class MyTwitterApi(config: Config) ...
So I need to do pass configuration.underlying to my constructor, how is this possible using DI in this AbstractModule?
I need this instance to be a singleton also.
You can use provider to setup your module with eagerSingleton
import com.google.inject.{AbstractModule, Provider}
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
val twitterApiProvider: Provider[TwitterApi] =
() => new MyTwitterApi(configuration.underlying)
bind(classOf[TwitterApi])
.toProvider(twitterApiProvider)
.asEagerSingleton
}
}
You can find a working example with sample classes at - https://scastie.scala-lang.org/sarveshseri/ujwvJJNnTpiWDqdkBJQoFw/2
I think you want something like this:
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
val myTwitterApiInstance = new MyTwitterApi(configuration.underlying)
bind(classOf[TwitterApi])
.toInstance(myTwitterApiInstance)
}
}
Or another approach would be to provide a binding for Config but if your MyTwitterApi doesn't have #Inject annotation this won't help.

Guice bind a class and its adapter

I would like implement a Guice module which binds an adapter to a named argument, but to create this adapter, it needs to instantiate another class, which also need injected arguments.
Here is the example in Scala:
trait Service
class UserService #Inject()(#Named(value = "foo") foo: String) extends Service
trait Adapter
class AdapterImpl(service: Service) extends Adapter
class AdapterRef(val adapter: Adapter)
class Module extends AbstractModule {
override def configure(): Unit = {
val fooValue = "bar"
bind(classOf[String])
.annotatedWith(Names.named("foo"))
.toInstance(fooValue)
val userService = new UserService(fooValue) //It should be instantiated by Guice somehow
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toInstance(new AdapterRef(new AdapterImpl(userService))) //Thats kinda ok
}
}
Can someone point me to the right direction?
Thank you,
Gabor
You can use a Provides method within your module, which lets you remove the binding. This is my best effort at Scala so if the syntax is incorrect let me know.
#Provides() #Singleton() def provideAdapterRef(service: Service): AdapterRef = {
return new AdapterRef(new AdapterImpl(service))
}
Note the use of Singleton to imitate your examples use of toInstance. If you don't need it to always provide the same instance I would recommend removing the scope and letting it create a new one every time.
An alternative solution is to use a Provider. This requires you to keep a modified version of the binding in your module and create an extra class, but it can be a cleaner solution if your Provider is more complex.
//Can inject UserService as well, or provide annotations to configure which
//implementation of Service you get if you have more than one.
class UserServiceProvider #Inject()(service: Service) extends Provider[AdapterRef] {
override def get(): AdapterRef {
return new AdapterRef(new AdapterImpl(service))
}
}
Then you can change your binding in the module to
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toProvider(classOf[UserServiceProvider])
.in(classOf[Singleton])
Here note the use of in(Singleton) to replicate your toInstance behavior.

Dependency Injection to Play Framework 2.5 modules

I have a module class with the following signature:
class SilhouetteModule extends AbstractModule with ScalaModule {
I would like to inject configuration:
class SilhouetteModule #Inject() (configuration: Configuration) extends AbstractModule with ScalaModule {
But it fails with the following error.
No valid constructors
Module [modules.SilhouetteModule] cannot be instantiated.
The Play documentation mentions that
In most cases, if you need to access Configuration when you create a component, you should inject the Configuration object into the component itself or...
, but I can't figure out how to do it successfully. So the question is, how do I inject a dependency into a module class in Play 2.5?
There are two solutions to solve your problem.
First one (and the more straight forward one):
Do not extend the com.google.inject.AbstractModule. Instead use the play.api.inject.Module. Extending that forces you to override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]]. Within that method you could do all your bindings and you get the configuration inserted as a method-parameter.
Second one (and the more flexible one):
Depending on your needs of the components you want to inject, you could define a provider for the component you want to bind. In that provider you could inject whatever you want. E.g.
import com.google.inject.Provider
class MyComponentProvider #Inject()(configuration:Configuration) extends Provider[MyComponent] {
override def get(): MyComponent = {
//do what ever you like to do with the configuration
// return an instance of MyComponent
}
}
Then you could bind your component within your module:
class SilhouetteModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[MyComponent]).toProvider(classOf[MyComponentProvider])
}
}
The advantage of the second version, is that you are able to inject what ever you like. In the first version you get "just" the configuration.
Change your constructor signature from:
class SilhouetteModule #Inject() (configuration: Configuration) extends AbstractModule with ScalaModule
to:
class SilhouetteModule(env: Environment, configuration: Configuration) extends AbstractModule with ScalaModule
see here for more info:
https://github.com/playframework/playframework/issues/8474

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!
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

Guice in Scala: Module for a class that has a DI-constructor itself

I'm using codingwell/scala-guice and trying to inject DAO-classes into constructors of other components/classes.
In the first attempt, I only used one DAO-class to see if it works:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
val dao1 = new FirstDaoImpl
bind(new TypeLiteral[FirstDaoTrait] {}).toInstance(dao1)
}
}
The binding works as expected, it can be used for constructor injection.
In the second step, I wanted to add another DAO class to the module. However, that DAO-class depends on the first DAO:
class SecondDaoImpl #Inject()(firstDao: FirstDaoTrait) extends SecondDaoTrait
I'm not sure how to add the necessary binding to the existing module. Repeating the first step would result in this:
val dao2 = new SecondDaoImpl(???)
bind(new TypeLiteral[SecondDaoTrait] {}).toInstance(dao2)
But of course this class can only be instantiated by providing the first DAO (therefore the "???"). How can I do this?
Use bind and let scala-guice resolve the dependencies for you:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
bind[FirstDaoTrait].to[FirstDaoImpl]
bind[SecondDaoTrait].to[SecondDaoImpl]
}
}
And now using the injector:
val injector = Guice.createInjector(new DaoModule())
val secondDao = injector.instance[SecondDaoTrait]