使用 akka 编组的 scala 中的通用 return 类型
Generic return type in scala with akka marshalling
我得到了以下相当简单的代码:
case class InverterResponse(body: InverterBody) extends SolarResponse
case class InverterBody(data: InverterData)
case class InverterData(dayEnergy: DayEnergy)
case class DayEnergy(unit: String, values: Values)
case class Values(value: Int)
case class MeterResponse(body: MeterBody) extends SolarResponse
case class MeterBody(data: MeterData)
case class MeterData(powerRealSum: BigDecimal, powerRealPhase1: BigDecimal, powerRealPhase2: BigDecimal, powerRealPhase3: BigDecimal)
class SolarWebConnector extends JsonSupport {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val httpClient = Http().outgoingConnection(host = "192.168.178.22", port = 80)
def getInverterRealtimeData(): InverterData = {
val inverterRealtimeURLPath = s"""/solar_api/v1/GetInverterRealtimeData.cgi?scope=System"""
val flowGet: Future[InverterResponse] = sendRequest[InverterResponse](inverterRealtimeURLPath)
val start = System.currentTimeMillis()
val result = Await.result(flowGet, 5 seconds)
val end = System.currentTimeMillis()
println(s"Result in ${end - start} millis: $result")
result.body.data
}
private def sendRequest[T](inverterRealtimeURLPath: String) : Future[T] = {
val flowGet: Future[T] =
Source.single(
HttpRequest(
method = HttpMethods.GET,
uri = Uri(inverterRealtimeURLPath))
)
.via(httpClient)
.mapAsync(1)(response => Unmarshal(response.entity).to[T])
.runWith(Sink.head)
flowGet
}
def getMeterRealtimeData(): String = {
"test"
}
}
JsonSupport 包含 json 格式定义以将传入 json 编组到响应案例 类。只要我不尝试为 sendRequest 方法定义一个通用版本,它就可以正常工作,它可以是 return InverterResponse 或 MeterResponse 类型。它编译得很好,但我得到:
Error:(54, 63) Play 2 Compiler:
/Users/tbecker/workspaces/home-integrator/app/services/SolarWebConnector.scala:54:63: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.Unmarshaller[akka.http.scaladsl.model.ResponseEntity,T]
.mapAsync(1)(response => Unmarshal(response.entity).to[T])
^
大约 2 年没有真正使用过 scala...所以我的知识可能有点生锈...
通过深入研究资源和文档,我自己找到了答案。
https://doc.akka.io/docs/akka-http/current/scala/http/common/unmarshalling.html
Umarshall 需要一个隐式的 Unmarshaller。像这样在方法签名中提供它可以解决问题:
private def sendRequest[T](inverterRealtimeURLPath: String)(隐式 m: Unmarshaller[ResponseEntity, T]) : Future[T] = {
我得到了以下相当简单的代码:
case class InverterResponse(body: InverterBody) extends SolarResponse
case class InverterBody(data: InverterData)
case class InverterData(dayEnergy: DayEnergy)
case class DayEnergy(unit: String, values: Values)
case class Values(value: Int)
case class MeterResponse(body: MeterBody) extends SolarResponse
case class MeterBody(data: MeterData)
case class MeterData(powerRealSum: BigDecimal, powerRealPhase1: BigDecimal, powerRealPhase2: BigDecimal, powerRealPhase3: BigDecimal)
class SolarWebConnector extends JsonSupport {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val httpClient = Http().outgoingConnection(host = "192.168.178.22", port = 80)
def getInverterRealtimeData(): InverterData = {
val inverterRealtimeURLPath = s"""/solar_api/v1/GetInverterRealtimeData.cgi?scope=System"""
val flowGet: Future[InverterResponse] = sendRequest[InverterResponse](inverterRealtimeURLPath)
val start = System.currentTimeMillis()
val result = Await.result(flowGet, 5 seconds)
val end = System.currentTimeMillis()
println(s"Result in ${end - start} millis: $result")
result.body.data
}
private def sendRequest[T](inverterRealtimeURLPath: String) : Future[T] = {
val flowGet: Future[T] =
Source.single(
HttpRequest(
method = HttpMethods.GET,
uri = Uri(inverterRealtimeURLPath))
)
.via(httpClient)
.mapAsync(1)(response => Unmarshal(response.entity).to[T])
.runWith(Sink.head)
flowGet
}
def getMeterRealtimeData(): String = {
"test"
}
}
JsonSupport 包含 json 格式定义以将传入 json 编组到响应案例 类。只要我不尝试为 sendRequest 方法定义一个通用版本,它就可以正常工作,它可以是 return InverterResponse 或 MeterResponse 类型。它编译得很好,但我得到:
Error:(54, 63) Play 2 Compiler:
/Users/tbecker/workspaces/home-integrator/app/services/SolarWebConnector.scala:54:63: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.Unmarshaller[akka.http.scaladsl.model.ResponseEntity,T]
.mapAsync(1)(response => Unmarshal(response.entity).to[T])
^
大约 2 年没有真正使用过 scala...所以我的知识可能有点生锈...
通过深入研究资源和文档,我自己找到了答案。
https://doc.akka.io/docs/akka-http/current/scala/http/common/unmarshalling.html
Umarshall 需要一个隐式的 Unmarshaller。像这样在方法签名中提供它可以解决问题:
private def sendRequest[T](inverterRealtimeURLPath: String)(隐式 m: Unmarshaller[ResponseEntity, T]) : Future[T] = {