Error converting Play Silhouette Module from Guice To Macwire - scala

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!

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

Related

Scala - Injecting Generic type using guice when dependency class is also using same generic type

I want to inject dependency with Generic type using Guice. Find below example in scala which replicate the issue.
ProductModel.scala
trait BaseProduct
case class Product() extends BaseProduct
CartService.scala
class CartService[A <: BaseProduct] #Inject()(productService : ProductService[A]) {
def getCartItems = productService.getProduct
}
ProductService.scala
class ProductService[A]{
def getProduct = println("ProductService")
}
Main.scala
object Main extends App {
val injector = Guice.createInjector(new ShoppingModule)
val cartService = injector.getInstance(classOf[CartService[Product]])
cartService.getCartItems
}
class ShoppingModule extends AbstractModule with ScalaModule {
override def configure(): Unit = {
bind[BaseProduct].to(scalaguice.typeLiteral[Product])
}
}
while running this Main.scala app getting below error.
service.ProductService<A> cannot be used as a key; It is not fully specified.
I have tried binding using codingwell library. But it doesn't help to identify ProductService Type.
When you create instance of cartService at that time use typeLiteral to create instance like
val cartService = injector.getInstance(Key.get(scalaguice.typeLiteral[CartService[Product]])
if you create instance like above you don't need to create module.
Create injector using default Module (i.e. useful if you have any other bindings in default Module.scala at application level)
val appBuilder = new GuiceApplicationBuilder()
val injector = Guice.createInjector(appBuilder.applicationModule())
and if you don't have any module you can skip passing module as argument and create injector without passing any module as well like
val injector = Guice.createInjector()

Importing generic implicits from class instances

I'm trying to make a generic implicit provider which can create an implicit value for a given type, something in the lines of:
trait Evidence[T]
class ImplicitProvider[T] {
class Implementation extends Evidence[T]
implicit val evidence: Evidence[T] = new Implementation
}
To use this implicit, I create a val provider = new ImplicitProvider[T] instance where necessary and import from it import provider._. This works fine as long as there is just one instance. However sometimes implicits for several types are needed in one place
case class A()
case class B()
class Test extends App {
val aProvider = new ImplicitProvider[A]
val bProvider = new ImplicitProvider[B]
import aProvider._
import bProvider._
val a = implicitly[Evidence[A]]
val b = implicitly[Evidence[B]]
}
And this fails to compile with could not find implicit value for parameter and not enough arguments for method implicitly errors.
If I use implicit vals from providers directly, everything starts to work again.
implicit val aEvidence = aProvider.evidence
implicit val bEvidence = bProvider.evidence
However I'm trying to avoid importing individual values, as there are actually several implicits inside each provider and the goal is to abstract them if possible.
Can this be achieved somehow or do I want too much from the compiler?
The issue is that when you import from both objects, you're bringing in two entities that have colliding names: evidence in aProvider and evidence in bProvider. The compiler cannot disambiguate those, both because of how its implemented, and because it'd be a bad idea for implicits, which can already be arcane, to be able to do things that cannot be done explicitly (disambiguating between clashing names).
What I don't understand is what the point of ImplicitProvider is. You can pull the Implementation class out to the top level and have an object somewhere that holds the implicit vals.
class Implementation[T] extends Evidence[T]
object Evidence {
implicit val aEvidence: Evidence[A] = new Implementation[A]
implicit val bEvidence: Evidence[B] = new Implementation[B]
}
// Usage:
import Evidence._
implicitly[Evidence[A]]
implicitly[Evidence[B]]
Now, there is no name clash.
If you need to have an actual ImplicitProvider, you can instead do this:
class ImplicitProvider[T] { ... }
object ImplicitProviders {
implicit val aProvider = new ImplicitProvider[A]
implicit val bProvider = new ImplicitProvider[B]
implicit def ImplicitProvider2Evidence[T: ImplicitProvider]: Evidence[T]
= implicitly[ImplicitProvider[T]].evidence
}
// Usage
import ImplicitProviders._
// ...

Injecting playFramework dependancies to scala object using MacWire traits fail

Lets say I have bunch of car objects in my project, for example:
object Porsche extends Car {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
im extending Car which is just a trait to set a car structure:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
Now, in the start() method I want to use some api service that will give me a car key based on its id so I cant start the car.
So I have this CarApiService:
class CarApiService (wsClient: WSClient, configuration: Configuration) {
implicit val formats: Formats = DefaultFormats
def getCarkey(carId: String): Future[Option[CarKey]] = {
val carInfoServiceApi = s"${configuration.get[String]("carsdb.carsInfo")}?carId=$carId"
wsClient.url(carInfoServiceApi).withHttpHeaders(("Content-Type", "application/json")).get.map { response =>
response.status match {
case Status.OK => Some(parse(response.body).extract[CarKey])
case Status.NO_CONTENT => None
case _ => throw new Exception(s"carsdb failed to perform operation with status: ${response.status}, and body: ${response.body}")
}
}
}
}
I want to have the ability to use getCarkey() in my car objects, so I created a CarsApiServicesModule which will give my access to the carApiService and I can use its methods:
trait CarsApiServicesModule {
/// this supply the carApiService its confuguration dependancy
lazy val configuration: Config = ConfigFactory.load()
lazy val conf: Configuration = wire[Configuration]
/// this supply the carApiService its WSClient dependancy
lazy val wsc: WSClient = wire[WSClient]
lazy val carApiService: CarApiService = wire[CarApiService]
}
and now I want to add mix this trait in my car object this way:
object Porsche extends Car with CarsApiServicesModule {
// here I want to use myApiService
// for example: carApiService.getCarkey(carId)...
}
but when compiling this I get this error:
does anyone know what is the issue?
also, is that design make sense?
You need to keep in mind that wire is just a helper macro which tries to generate new instance creation code: it's quite dumb, in fact. Here, it would try to create a new instance of WSClient.
However, not all objects can be instantiated using a simple new call - sometimes you need to invoke "factory" method.
In this case, if you take a look at the readme on GitHub, you'll see that to instantiate the WSClient, you need to create it through the StandaloneAhcWSClient() object.
So in this case, wire won't help you - you'll need to simply write the initialisation code by hand. Luckily it's not too large.

Guice: Could not find a suitable constructor in com.twitter.inject.Injector

I am using Guice injections and Finatra with my service.
When trying to build a small test app I am getting this error:
Could not find a suitable constructor in com.twitter.inject.Injector. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
at com.twitter.inject.Injector.class(Injector.scala:9)
My Module with the injectors looks like this
object ServiceModule extends TwitterModule {
#Provides
#Singleton
def provideS2SAuthServiceConfig(): S2SAuthServiceConfig = {
val servicePath = DynamicProperty.getInstance("myorg.module.auth.servicePath").getString
val serviceUrl = DynamicProperty.getInstance("myorg.module.auth.serviceUrl").getString
val httpClient: Service[Request, Response] = Http.client.withTls(serviceUrl).newService(serviceUrl)
S2SAuthServiceConfig(httpClient, servicePath)
}
#Provides
#Singleton
def provideS2SAuthClient(injector: Injector): S2SAuthClient = {
val s2sAuthClientClass = DynamicProperty.getInstance("myorg.mymodule.s2s.s2sAuthClient").getString
val s2sAuthClientInstance = injector.instance(Class.forName(s2sAuthClientClass))
s2sAuthClientInstance.asInstanceOf[S2SAuthClient]
}
}
It works well when I inject these objects in the constructor of my classes, but I get the error when trying to get an object instance like this:
def main (args: Array[String]): Unit = {
val injector = new Injector(Guice.createInjector(ServiceModule))
val authClient = injector.instance[S2SAuthClientImpl](classOf[S2SAuthClientImpl])
val token = authClient.getToken("MyClientID", "MySecret", "MyScope")
println(token)
}
Any ideas why Guice is not able to find the constructor for the Twitter Injector class?

Why use scala's cake pattern rather than abstract fields?

I have been reading about doing Dependency Injection in scala via the cake pattern. I think I understand it but I must have missed something because I still can't see the point in it! Why is it preferable to declare dependencies via self types rather than just abstract fields?
Given the example in Programming Scala TwitterClientComponent declares dependencies like this using the cake pattern:
//other trait declarations elided for clarity
...
trait TwitterClientComponent {
self: TwitterClientUIComponent with
TwitterLocalCacheComponent with
TwitterServiceComponent =>
val client: TwitterClient
class TwitterClient(val user: TwitterUserProfile) extends Tweeter {
def tweet(msg: String) = {
val twt = new Tweet(user, msg, new Date)
if (service.sendTweet(twt)) {
localCache.saveTweet(twt)
ui.showTweet(twt)
}
}
}
}
How is this better than declaring dependencies as abstract fields as below?
trait TwitterClient(val user: TwitterUserProfile) extends Tweeter {
//abstract fields instead of cake pattern self types
val service: TwitterService
val localCache: TwitterLocalCache
val ui: TwitterClientUI
def tweet(msg: String) = {
val twt = new Tweet(user, msg, new Date)
if (service.sendTweet(twt)) {
localCache.saveTweet(twt)
ui.showTweet(twt)
}
}
}
Looking at instantiation time, which is when DI actually happens (as I understand it), I am struggling to see the advantages of cake, especially when you consider the extra keyboard typing you need to do for the cake declarations (enclosing trait)
//Please note, I have stripped out some implementation details from the
//referenced example to clarify the injection of implemented dependencies
//Cake dependencies injected:
trait TextClient
extends TwitterClientComponent
with TwitterClientUIComponent
with TwitterLocalCacheComponent
with TwitterServiceComponent {
// Dependency from TwitterClientComponent:
val client = new TwitterClient
// Dependency from TwitterClientUIComponent:
val ui = new TwitterClientUI
// Dependency from TwitterLocalCacheComponent:
val localCache = new TwitterLocalCache
// Dependency from TwitterServiceComponent
val service = new TwitterService
}
Now again with abstract fields, more or less the same!:
trait TextClient {
//first of all no need to mixin the components
// Dependency on TwitterClient:
val client = new TwitterClient
// Dependency on TwitterClientUI:
val ui = new TwitterClientUI
// Dependency on TwitterLocalCache:
val localCache = new TwitterLocalCache
// Dependency on TwitterService
val service = new TwitterService
}
I'm sure I must be missing something about cake's superiority! However, at the moment I can't see what it offers over declaring dependencies in any other way (constructor, abstract fields).
Traits with self-type annotation is far more composable than old-fasioned beans with field injection, which you probably had in mind in your second snippet.
Let's look how you will instansiate this trait:
val productionTwitter = new TwitterClientComponent with TwitterUI with FSTwitterCache with TwitterConnection
If you need to test this trait you probably write:
val testTwitter = new TwitterClientComponent with TwitterUI with FSTwitterCache with MockConnection
Hmm, a little DRY violation. Let's improve.
trait TwitterSetup extends TwitterClientComponent with TwitterUI with FSTwitterCache
val productionTwitter = new TwitterSetup with TwitterConnection
val testTwitter = new TwitterSetup with MockConnection
Furthermore if you have a dependency between services in your component (say UI depends on TwitterService) they will be resolved automatically by the compiler.
Think about what happens if TwitterService uses TwitterLocalCache. It would be a lot easier if TwitterService self-typed to TwitterLocalCache because TwitterService has no access to the val localCache you've declared. The Cake pattern (and self-typing) allows for us to inject in a much more universal and flexible manner (among other things, of course).
I was unsure how the actual wiring would work, so I've adapted the simple example in the blog entry you linked to using abstract properties like you suggested.
// =======================
// service interfaces
trait OnOffDevice {
def on: Unit
def off: Unit
}
trait SensorDevice {
def isCoffeePresent: Boolean
}
// =======================
// service implementations
class Heater extends OnOffDevice {
def on = println("heater.on")
def off = println("heater.off")
}
class PotSensor extends SensorDevice {
def isCoffeePresent = true
}
// =======================
// service declaring two dependencies that it wants injected
// via abstract fields
abstract class Warmer() {
val sensor: SensorDevice
val onOff: OnOffDevice
def trigger = {
if (sensor.isCoffeePresent) onOff.on
else onOff.off
}
}
trait PotSensorMixin {
val sensor = new PotSensor
}
trait HeaterMixin {
val onOff = new Heater
}
val warmer = new Warmer with PotSensorMixin with HeaterMixin
warmer.trigger
in this simple case it does work (so the technique you suggest is indeed usable).
However, the same blog shows at least other three methods to achieve the same result; I think the choice is mostly about readability and personal preference. In the case of the technique you suggest IMHO the Warmer class communicates poorly its intent to have dependencies injected. Also to wire up the dependencies, I had to create two more traits (PotSensorMixin and HeaterMixin), but maybe you had a better way in mind to do it.
In this example I think there is no big difference. Self-types can potentially bring more clarity in cases when a trait declares several abstract values, like
trait ThreadPool {
val minThreads: Int
val maxThreads: Int
}
Then instead of depending on several abstract values you just declare dependency on a ThreadPool.
Self-types (as used in Cake pattern) for me are just a way to declare several abstract members at once, giving those a convenient name.