Error converting Play Silhouette Module from Guice To Macwire

99 views Asked by At

I am trying to convert from Guice to Macwire as a dependency injection framework. It is going fine apart from this Silhouette Module where I am getting a compilation error. Error at bottom.

Working Module in Guice:

  class SilhouetteModule @Inject()(environment: play.api.Environment, configuration: 
   Configuration) extends AbstractModule with ScalaModule {

  override def configure() = {
      val iamConfig = IAMConfiguration
        .fromConfiguration(configuration)
        .fold(throw _, identity)

      val htPasswdFile = File.apply(configuration.get[String]("file"))

      bind[IdentityService[User]].toInstance(SimpleIdentityService.fromConfig(iamConfig))
      bind[Silhouette[BasicAuthEnv]].to[SilhouetteProvider[BasicAuthEnv]]
      bind[RequestProvider].to[BasicAuthProvider].asEagerSingleton()
      bind[PasswordHasherRegistry].toInstance(PasswordHasherRegistry(new BCryptPasswordHasher()))
      bind[AuthenticatorService[DummyAuthenticator]].toInstance(new DummyAuthenticatorService)
      bind[AuthInfoRepository].toInstance(HtpasswdAuthInfoRepository.fromFile(htPasswdFile))
      bind[SecuredErrorHandler].to[RestHttpSecuredErrorHandler]
  }

    @Provides
    def provideEnvironment(identityService: IdentityService[User], authenticatorService: 
       AuthenticatorService[DummyAuthenticator], eventBus: EventBus, requestProvider: 
       RequestProvider): Environment[BasicAuthEnv] =
        Environment[BasicAuthEnv](
          identityService, 
          authenticatorService, 
          Seq(requestProvider), 
          eventBus
       )
   }
}

Equivalent attempt in Macwire:

trait SilhouetteModule extends BuiltInComponents {
   import com.softwaremill.macwire._

   val iamConfig = IAMConfiguration
     .fromConfiguration(configuration)
     .fold(throw _, identity)

   val htPasswdFile = File.apply(configuration.get[String]("file"))

   lazy val identityService: IdentityService[User] =
     SimpleIdentityService.fromConfig(iamConfig)

   lazy val basicAuthEnv: Silhouette[BasicAuthEnv] = wire[SilhouetteProvider[BasicAuthEnv]]

   lazy val requestProvider: RequestProvider = wire[BasicAuthProvider]

   lazy val passwordHasherRegistry: PasswordHasherRegistry = PasswordHasherRegistry(
      new BCryptPasswordHasher())
   lazy val authenticatorService: AuthenticatorService[DummyAuthenticator] =
      new DummyAuthenticatorService
   lazy val authInfoRepo: AuthInfoRepository =
      HtpasswdAuthInfoRepository.fromFile(htPasswdFile)

   lazy val errorHandler: SecuredErrorHandler = wire[RestHttpSecuredErrorHandler]

   lazy val env: Environment[BasicAuthEnv] = Environment[BasicAuthEnv](
     identityService,
     authenticatorService,
     Seq(requestProvider),
     eventBus
   )
   def eventBus: EventBus
 }

The Macwire example does not compile: I get an error: Cannot find a value of type: [com.mohiva.play.silhouette.api.actions.SecuredAction] lazy val basicAuthEnv: Silhouette[BasicAuthEnv] = wire[SilhouetteProvider[BasicAuthEnv]]

Sorry its a lot of code but I thought a side-by-side comparison would be more helpful. Any help would be great!

1

There are 1 answers

2
Mateusz Kubuszok On BEST ANSWER

MacWire doesn't magically creates values - if it needs to construct a value, it looks what values are taken by the constructor and - if by looking at all values available in the scope it can unambiguously find all the parameters of the constructor, the macro creates code new Class(resolvedArg1, resolvedArg2, ...).

So

  • all of these values have to be in Scope - they can be constructed by MacWire, or be abstract members implemented by some mixin, but still you have to write them down explicitly
  • if you have 2 values of the same type in scope - MacWire cannot generate the code because how it would know which value to pick? (Well, if one of the values is in closer "closer" than the other it can, but if they are equally close it cannot be resolved)

So if you get the error:

Cannot find a value of type: [com.mohiva.play.silhouette.api.actions.SecuredAction]

it means that you haven't declared any value of type com.mohiva.play.silhouette.api.actions.SecuredAction in SilhouetteModule nor in BuiltInComponents.

If this is something that is provided by another trait you can add abstract declaration here

val securedAction: SecuredAction // abstract val

and implement it somewhere else (be careful to avoid circular dependencies!).