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 type JsonReader[A]
). Therefore, as you already mentioned, A
could be anything, so you can't call the entities
method. If you convert to StandardReturn[A]
instead of just A
, this problem is resolved.
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[StandardReturn[A]] <- just convert to what you actually want
.entities
Additionally, you have to replace the type parameter in new Example().transform[StandardReturn[System]](response)
by just System
instead of StandardReturn[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 the systemFormat
of type JsonReader[System]
(in SystemProtocol
). The compiler does not give up yet: he tries to find an implicit conversion from JsonReader[System]
to JsonReader[StandardFormat[System]]
, and that is just the method entityFormat
you defined. Yeah!
One last remark: You could further simplify the method entityFormat
if you replace jsonFormat(StandardReturn.apply[A], "total-count", "entities")
by jsonFormat2(StandardReturn.apply[A])
, as noted in the documentation.