我正在寻找一种方法来定义一个Reads
,它允许我映射包含以下结构的JSON:
{
"offers": [
[
{
"id": "1234",
(etc.)
}
]
]
}
模拟这样的case class TransportOffer(offers: List[Offer])
不幸的是,我还没能做到这一点。这是我的代码:
implicit val transportOfferReads: Reads[TransportOffer] = (
(JsPath "offers").read[List[List[Offer]]].flatMap(r => r.flatten)
)(TransportOffer.apply _)
在这种情况下,平坦化是不可能的,因为flatMap需要另一个read。如何将扁平的List包装成另一个Reads?或者有更简单的方法吗?
我将呈现3个选项:
- 在短时间内变平:
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))
}
然后调用:
Json.parse(jsonString).validate[TransportOffer].foreach(println)
输出:
TransportOffer(List(Offer(1234)))
在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))
}
在Scastie上运行的代码。
- 首先将json转换为您想要的模型。为此,定义
transformer
:
val jsonTransformer = (__ "offers").json
.update(__.read[JsArray].map{o => {
JsArray(o.value.flatMap(_.asOpt[JsArray].map(_.value)).flatten)
}})
然后,假设我们有case类和它们的格式化器:
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]
}
可以调用:
Json.parse(jsonString).transform(jsonTransformer) match {
case JsSuccess(value, _) =>
value.validate[TransportOffer].foreach(println)
case JsError(errors) =>
println(errors)
???
}
输出是:
TransportOffer(List(Offer(1234)))
在Scastie上运行的代码。