Scala Play 阅读:How to Flatten Json containing Array of arrays to model
Scala Play Read: How to Flatten Json containing Array of arrays to model
我正在寻找一种定义 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 需要另一个读取。我如何将扁平化的列表包装到另一个读取中?
或者有更简单的方法吗?
我将给出 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 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。
我正在寻找一种定义 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 需要另一个读取。我如何将扁平化的列表包装到另一个读取中? 或者有更简单的方法吗?
我将给出 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 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。