1

I'm trying to port this repo from Guice to Scaldi. I'm stack in this code from /app/utils/di/SilhouetteModule.scala (lines 60-65):

  Map(
    credentialsProvider.id -> credentialsProvider,
    facebookProvider.id -> facebookProvider,
    googleProvider.id -> googleProvider,
    twitterProvider.id -> twitterProvider
  ),

And here is where I'm now

class SilhouetteModule extends Module {

  bind[DelegableAuthInfoDAO[PasswordInfo]] to new PasswordInfoDAO
  bind[DelegableAuthInfoDAO[OAuth1Info]] to new OAuth1InfoDAO
  bind[DelegableAuthInfoDAO[OAuth2Info]] to new OAuth2InfoDAO
  bind[CacheLayer] to new PlayCacheLayer
  bind[HTTPLayer] to new PlayHTTPLayer
  bind[IDGenerator] to new SecureRandomIDGenerator
  bind[PasswordHasher] to new BCryptPasswordHasher
  bind[EventBus] to new EventBus


  bind[Environment[User, CachedCookieAuthenticator]] toProvider new Environment[User, CachedCookieAuthenticator](
    inject [UserService],
    inject [AuthenticatorService],
    // **this is where I don't know what to do**
    Map(
      credentialsProvider.id -> credentialsProvider,
      facebookProvider.id -> facebookProvider,
      googleProvider.id -> googleProvider,
      twitterProvider.id -> twitterProvider
    ),
    inject [EventBus]
  )
//... *Provider bindings below

What can I do to inject the Map like in the code above?

Can Scaldi bind to a function (like @Provides annotation in Guice) ?

thanks

Mironor
  • 1,157
  • 10
  • 25

1 Answers1

1

In general your code looks pretty good. In scaldi toProvider or to get a function as an argument, so you always bind a function which will be called at some point by library in order to get a new instance of the bound dependency.

In the guice example credentialsProvider, facebookProvider, googleProvider and twitterProvider are injected in the provideEnvironment. You need to do the same in scaldi:

binding toProvider {
  val credentialsProvider = inject [CredentialsProvider]
  val facebookProvider = inject [FacebookProvider]
  val googleProvider = inject [GoogleProvider]
  val twitterProvider = inject [TwitterProvider]

  new Environment[User, CachedCookieAuthenticator](
    inject [UserService],
    inject [AuthenticatorService],
    Map(
      credentialsProvider.id -> credentialsProvider,
      facebookProvider.id -> facebookProvider,
      googleProvider.id -> googleProvider,
      twitterProvider.id -> twitterProvider
    ),
    inject [EventBus])
}

All of these dependencies are bound with toProvider, which means that every time you inject googleProvider, for example, a new instance of it would be created. So I first assigned them to the val and then used them to create a new instance of the Environment.

Just to show and example of another binding, here is how you can bind GoogleProvider:

binding toProvider new GoogleProvider(inject [CacheLayer], inject [HTTPLayer], OAuth2Settings(
  authorizationURL = inject [String] ("silhouette.google.authorizationURL"),
  accessTokenURL = inject [String] ("silhouette.google.accessTokenURL"),
  redirectURL = inject [String] ("silhouette.google.redirectURL"),
  clientID = inject [String] ("silhouette.google.clientID"),
  clientSecret = inject [String] ("silhouette.google.clientSecret"),
  scope = inject [String] ("silhouette.google.scope")))

I used binding instead of bind [...] because in this case the type of the binding and the actual value, that you want to bind, have the same type, so scaldi allows you to simplify it a little bit.

I also just injected all of the play configuration instead of using Play directly - scaldi-play provides an integration with play configuration.

Finally you can also extract the Map in it's own binding like this:

bind [Map[String, Provider]] toProvider {
  val credentialsProvider = inject [CredentialsProvider]
  val facebookProvider = inject [FacebookProvider]
  val googleProvider = inject [GoogleProvider]
  val twitterProvider = inject [TwitterProvider]

  Map(
    credentialsProvider.id -> credentialsProvider,
    facebookProvider.id -> facebookProvider,
    googleProvider.id -> googleProvider,
    twitterProvider.id -> twitterProvider
  )
}

Environment binding in this case will look like this:

binding toProvider new Environment[User, CachedCookieAuthenticator](
  inject [UserService],
  inject [AuthenticatorService],
  inject [Map[String, Provider]],
  inject [EventBus])
tenshi
  • 26,268
  • 8
  • 76
  • 90
  • I just successfully finished the port from guice to scaldi and I was wondering if there is a way to setup Global object's getControllerInstance method to inject controllers on-the-fly without declaring them in WebModule? – Mironor Jul 04 '14 at 22:53
  • @Mironor I think this would be helpful to you: https://github.com/scaldi/scaldi/issues/14 Feel free to leave a comment there if you have thoughts on this issue – tenshi Jul 05 '14 at 13:52