[英]Scala class with generic types
I am trying to write a thin Scala wrapper around the Java Aws Lambda Client.我正在尝试围绕 Java Aws Lambda 客户端编写一个瘦 Scala 包装器。
This class should accept 2 generic parameters:这个类应该接受 2 个通用参数:
Something along the lines of:类似的东西:
import com.amazonaws.services.lambda.model.InvokeRequest
import com.amazonaws.services.lambda.{AWSLambda, AWSLambdaClientBuilder}
import org.json4s.native.Serialization
import org.json4s.native.Serialization.{read, write}
class LambdaInvoker[A <: AnyRef, B <: AnyRef](val client: AWSLambda = AWSLambdaClientBuilder.defaultClient()) {
implicit val serialization: Serialization.type = org.json4s.native.Serialization
def call(input: A, function: String): B = {
val request = new InvokeRequest().withFunctionName(function).withPayload(write(input))
val result = client.invoke(request)
val rawJsonResponse = new String(result.getPayload.array(), "UTF-8")
read(rawJsonResponse)
}
}
This works fine when I have both input and outputs to the call, but can't figure out what's the best "Scala" way of dealing with when A or B should not be present.当我有调用的输入和输出时,这很好用,但是当 A 或 B 不应该存在时,无法弄清楚什么是最好的“Scala”处理方式。 I was looking for ways of getting the runtime type of A or B, checking against Unit, then base the logic on that, but couldn't find an obvious way (probably due to type erasure?)我一直在寻找获取 A 或 B 的运行时类型的方法,检查 Unit,然后基于该逻辑,但找不到明显的方法(可能是由于类型擦除?)
If there is a different pattern I can apply here, without generic types but with Optionals, or anything else which achieves the same thing, that's also great.如果我可以在这里应用不同的模式,没有泛型类型但有 Optionals,或者其他任何可以实现相同目的的东西,那也很棒。
Here is a simplified example of how you could use typeclass pattern.这是一个如何使用类型类模式的简化示例。 I'm going to define a local one that is responsible for both writing and reading an object我将定义一个负责写入和读取对象的本地对象
object LambdaInvoker {
trait RW[A] {
def addPayload(a: A, r: InvokeRequest): InvokeRequest
def readResponse(r: InvokeResult): A
}
Now, we need to define some instances (as implicits) with actual implementations.现在,我们需要使用实际实现定义一些实例(作为隐式)。 We have two cases: either it's Unit, and then we know how to handle that specifically, or it's something JSON-encodable.我们有两种情况:要么是 Unit,然后我们知道如何具体处理它,要么是 JSON 可编码的东西。
To make everything work, we would have to use implicit prioritization technique of putting a fallback into a separate trait/class that we extend from.为了使一切正常,我们必须使用隐式优先级技术将回退放入我们扩展的单独特征/类中。 Here's a way to handle Unit
by not doing anything at all:这是一种完全不做任何事情来处理Unit
的方法:
object RW extends RWFallback {
// special cases go into this object
implicit val unitRW: RW[Unit] = new RW[Unit] {
def addPayload(a: Unit, r: InvokeRequest) = r
def readResponse(r: InvokeResult) = ()
}
}
And our fallback will be using json4s.我们的后备将使用 json4s。 Json4s requires something called a Manifest
, which is a part of a legacy scala reflection API, and we can require just that, without limiting ourselves to AnyRef
. Json4s 需要一个叫做Manifest
东西,它是遗留 scala 反射 API 的一部分,我们可以只需要它,而不限制我们自己使用AnyRef
。
trait RWFallback {
// fallback to json4s if not special cased
implicit def fallbackRW[A: Manifest]: RW[A] = new RW[A] {
implicit val serialization: Serialization.type = org.json4s.native.Serialization
implicit val formats = org.json4s.DefaultFormats
def addPayload(a: A, r: InvokeRequest) = r.withPayload(write(a))
def readResponse(r: InvokeResult) = read(new String(r.getPayload.array(), "UTF-8"))
}
}
This all has been inside object LambdaInvoker
, since it's limited to only LambdaInvoker stuff.这一切都在object LambdaInvoker
,因为它仅限于 LambdaInvoker 的东西。
}
Now, for the implementation, you have to do the following:现在,为了实现,您必须执行以下操作:
A: LambdaInvoker.RW
)需要参与数据类型的 RW 实例(使用隐式参数列表或上下文绑定语法完成,例如A: LambdaInvoker.RW
)class LambdaInvoker[A: RW, B: RW](val client: AWSLambda = AWSLambdaClientBuilder.defaultClient()) {
// "summon" the implicit values and give them a name, so we can refer to them
private[this] val rwA = implicitly[RW[A]]
private[this] val rwB = implicitly[RW[B]]
def call(input: A, function: String): B = {
// delegate serialization
val request = rwA.addPayload(input, new InvokeRequest().withFunctionName(function))
val result = client.invoke(request)
// delegate parsing
rwB.readResponse(result)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.