I am looking for a way to define a Reads
which allows me to map a JSON containing the following structure:
{
"offers": [
[
{
"id": "1234",
(etc.)
}
]
]
}
to model such case class TransportOffer(offers: List[Offer])
Unfortunately I haven't been able to do this yet. This is my code:
implicit val transportOfferReads: Reads[TransportOffer] = (
(JsPath \ "offers").read[List[List[Offer]]].flatMap(r => r.flatten)
)(TransportOffer.apply _)
In this case the flattening is not possible, as flatMap expects another Reads. How would I wrap the flattened List into another Reads? Or is there a simpler way?
I'll present 3 options:
case class Offer(id: String)
object Offer {
implicit val format: OFormat[Offer] = Json.format[Offer]
}
case class TransportOffer(offers: List[Offer])
object TransportOffer {
implicit val transportOfferReads: Reads[TransportOffer] =
(JsPath \ "offers").read[List[List[Offer]]].map(x => TransportOffer(x.flatten))
}
Then calling:
Json.parse(jsonString).validate[TransportOffer].foreach(println)
outputs:
TransportOffer(List(Offer(1234)))
Code run at Scastie
Reads
:implicit val transportOfferReads: Reads[TransportOffer] = (json: JsValue) => {
json \ "offers" match {
case JsUndefined() =>
JsError("offers undefined")
case JsDefined(value) =>
value.validate[List[List[Offer]]].map(x => TransportOffer(x.flatten))
}
Code run at Scastie.
transformer
:val jsonTransformer = (__ \ "offers").json
.update(__.read[JsArray].map{o => {
JsArray(o.value.flatMap(_.asOpt[JsArray].map(_.value)).flatten)
}})
Then, assuming we have the case classes and their formatters:
case class Offer(id: String)
object Offer {
implicit val format: OFormat[Offer] = Json.format[Offer]
}
case class TransportOffer(offers: List[Offer])
object TransportOffer {
implicit val format: OFormat[TransportOffer] = Json.format[TransportOffer]
}
We can call:
Json.parse(jsonString).transform(jsonTransformer) match {
case JsSuccess(value, _) =>
value.validate[TransportOffer].foreach(println)
case JsError(errors) =>
println(errors)
???
}
Output is:
TransportOffer(List(Offer(1234)))
Code run at Scastie.