We have an API that always has a total-count
and entities
in the response, but the entities
are of different types. What I'm trying to do is make the parsing & converting to case-classes more generic.
So trying with the following types
case class StandardReturn[A](
`total-count`: Double,
entities: List[A]
)
case class System(
id: String,
name: String
)
And the following example:
object SystemProtocol extends DefaultJsonProtocol {
implicit val systemFormat: RootJsonFormat[System] =
jsonFormat2(System)
implicit def entityFormat[A: JsonFormat] =
jsonFormat(StandardReturn.apply[A], "total-count", "entities")
}
import SystemProtocol._
val response = """{
"total-count": 10,
"entities": [
{ "id": "1", "name": "me" }
]
}"""
class Example {
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[A]
.entities // Where I'm running into trouble
}
object Example {
val transformed = new Example().transform[StandardReturn[System]](response)
}
Example.transformed
Which is understandably giving me
Error:(34, 42) value entities is not a member of type parameter A
entityString.parseJson.convertTo[A].entities // Where I'm running into trouble
^
How would I set up the case classes / types so that transform
could be assured that entities
will always exist after converting to type A
(where A
is StandardReturn[A]
)? I'm not too familiar with scala's type system, thank you for help.
In your Code, the type parameter
A
has no bounds except the context bound to JsonReader (an implicit parameter of typeJsonReader[A]
). Therefore, as you already mentioned,A
could be anything, so you can't call theentities
method. If you convert toStandardReturn[A]
instead of justA
, this problem is resolved.Additionally, you have to replace the type parameter in
new Example().transform[StandardReturn[System]](response)
by justSystem
instead ofStandardReturn[System]
, as the method above was changed.The compiler now needs an implicit parameter of type
JsonReader[StandardFormat[System]]
. But in the implicit scope, there is only thesystemFormat
of typeJsonReader[System]
(inSystemProtocol
). The compiler does not give up yet: he tries to find an implicit conversion fromJsonReader[System]
toJsonReader[StandardFormat[System]]
, and that is just the methodentityFormat
you defined. Yeah!One last remark: You could further simplify the method
entityFormat
if you replacejsonFormat(StandardReturn.apply[A], "total-count", "entities")
byjsonFormat2(StandardReturn.apply[A])
, as noted in the documentation.