使用 MacWire 特性注入 play Framework 对 scala 对象的依赖性失败
Injecting playFramework dependancies to scala object using MacWire traits fail
假设我的项目中有一堆汽车对象,例如:
object Porsche extends Car {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
我正在扩展 Car,这只是设置汽车结构的特征:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
现在,在 start()
方法中,我想使用一些 api 服务,它会根据它的 ID 给我一把车钥匙,所以我无法启动汽车。
所以我有这个 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}")
}
}
}
}
我希望能够在我的汽车对象中使用 getCarkey()
,因此我创建了一个 CarsApiServicesModule,它可以让我访问 carApiService
并且我可以使用它的方法:
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]
}
现在我想以这种方式在我的汽车对象中添加 mix 这个特征:
object Porsche extends Car with CarsApiServicesModule {
// here I want to use myApiService
// for example: carApiService.getCarkey(carId)...
}
但是在编译时我得到这个错误:
有人知道问题出在哪里吗?
另外,这样的设计有意义吗?
您需要记住,wire
只是一个辅助宏,它试图生成新的实例创建代码:事实上,它非常愚蠢。在这里,它会尝试创建 WSClient
的新实例。
但是,并非所有对象都可以使用简单的 new
调用来实例化 - 有时您需要调用 "factory" 方法。
在这种情况下,如果您查看 readme on GitHub,您会发现要实例化 WSClient
,您需要通过 StandaloneAhcWSClient()
对象创建它。
所以在这种情况下,wire
对您没有帮助 - 您只需要手动编写初始化代码。幸运的是它不是太大。
假设我的项目中有一堆汽车对象,例如:
object Porsche extends Car {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
我正在扩展 Car,这只是设置汽车结构的特征:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
现在,在 start()
方法中,我想使用一些 api 服务,它会根据它的 ID 给我一把车钥匙,所以我无法启动汽车。
所以我有这个 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}")
}
}
}
}
我希望能够在我的汽车对象中使用 getCarkey()
,因此我创建了一个 CarsApiServicesModule,它可以让我访问 carApiService
并且我可以使用它的方法:
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]
}
现在我想以这种方式在我的汽车对象中添加 mix 这个特征:
object Porsche extends Car with CarsApiServicesModule {
// here I want to use myApiService
// for example: carApiService.getCarkey(carId)...
}
但是在编译时我得到这个错误:
有人知道问题出在哪里吗?
另外,这样的设计有意义吗?
您需要记住,wire
只是一个辅助宏,它试图生成新的实例创建代码:事实上,它非常愚蠢。在这里,它会尝试创建 WSClient
的新实例。
但是,并非所有对象都可以使用简单的 new
调用来实例化 - 有时您需要调用 "factory" 方法。
在这种情况下,如果您查看 readme on GitHub,您会发现要实例化 WSClient
,您需要通过 StandaloneAhcWSClient()
对象创建它。
所以在这种情况下,wire
对您没有帮助 - 您只需要手动编写初始化代码。幸运的是它不是太大。