Injecting playFramework dependancies to scala object using MacWire traits fail

157 Views Asked by At

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:

enter image description here

does anyone know what is the issue?

also, is that design make sense?

1

There are 1 best solutions below

0
On BEST ANSWER

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.