I'm trying to avoid to use a generic on Request
that contains an optional generic Body
to avoid to pass a generic everywhere when it's only needed when writing the body, and also because there's no type when body is not defined:
case class Body[A](content: A)(implicit val bodyWritable: BodyWritable[A])
case class Request(url: String, body: Option[Body[_]])
private def executeRequest(request: Request) = {
val wsClient: StandaloneWSClient = ???
val requestWithUrl = wsClient.url(request.url)
request.body.fold(requestWithUrl)(body => requestWithUrl.withBody(body.content)(body.bodyWritable))
}
The compilation failed with:
Error:(20, 90) type mismatch;
found : play.api.libs.ws.BodyWritable[(some other)_$1(in value body)]
required: play.api.libs.ws.BodyWritable[_$1(in value body)]
I'm wondering if there's a way to not type request.
I'm using "com.typesafe.play" %% "play-ws-standalone" % "2.0.4"
In short you cant do this way. When wildcard is involved, the type parameter of an expression is always different from others, even they come from the same variable. The type A body.content
and the type parameter A of body.bodyWritable
are resolved as different local anonymous types, even though they come from the same variable body
, but Scala does not know that, because they are separate expressions.
To resolve this, the most type-safe way (and recommended) is to add type parameter to Request and executeRequest to ensure the type is resolved as the same.
You can also create a local method that takes a type parameter to make sure the two expressions shares the same generic type:
private def executeRequest(request: Request) = {
val wsClient: StandaloneWSClient = ???
val requestWithUrl = wsClient.url(request.url)
def f[A](body: Body[A]) = requestWithUrl.withBody(body.content)(body.bodyWritable)
request.body.fold(requestWithUrl)(body => f(body)) // or shorten to request.body.fold(requestWithUrl)(f)
}
Alternatively, I sometimes move the calling site into the class where the type parameter is declared, in which the type parameter is guaranteed to be the same. Something like:
case class Body[A](content: A)(implicit val bodyWritable: BodyWritable[A]) {
def getRequest(req: WSRequest) = req.withBody(content)
}
case class Request(url: String, body: Option[Body[_]])
private def executeRequest(request: Request) = {
val wsClient: StandaloneWSClient = ???
val requestWithUrl = wsClient.url(request.url)
request.body.fold(requestWithUrl)(body => body.getRequest(requestWithUrl))
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.