Play 2.2 JSON Reads with combinators:如何处理嵌套的可选对象?
Posted
技术标签:
【中文标题】Play 2.2 JSON Reads with combinators:如何处理嵌套的可选对象?【英文标题】:Play 2.2 JSON Reads with combinators: how to deal with nested optional objects? 【发布时间】:2013-10-29 01:57:01 【问题描述】:在 Play Framework 2.2 中解析这个 JSON 结构我快疯了:
val jsonStr = """ personFirstName: "FirstName",
personLastName: "LastName"
positionLat: null,
positionLon: null """
我有 2 个案例类:
case class Position( val lat: Double, val lon: Double)
case class Person( firstName: String, lastName: String, p: Option[Position] )
如您所见,位置在 Person 案例类中不是强制性的。
我试图使用类似的方法获取 Person 的实例
implicit val reader = (
(__ \ 'personFirstName ).read[String] ~
(__ \ 'personLastName ).read[String] ~
( (__ \ 'positionLat ).read[Double] ~
(__ \ 'positionLon ).read[Double] )(Position)
)(Person)
但我很快意识到我不知道如何处理 Option[Position]
对象:如果指定了“lat”和“lon”而不是 null,则意图是实例化 Some(Position(lat,lon))
,否则实例化 @987654326 @。
你会怎么处理?
【问题讨论】:
【参考方案1】:我很确定有比我要发布的内容更好的方法来做你想做的事,但已经晚了,我现在想不通。我假设这里不能简单地更改您正在使用的 JSON 结构。
您可以提供一个构建器函数,该函数接受两个 可选 lat/lon 双精度值,如果它们都存在则产生一个位置。
import play.api.libs.functional.syntax._
import play.api.libs.json._
val jsonStr = """
"personFirstName": "FirstName",
"personLastName": "LastName",
"positionLat": null,
"positionLon": null """
case class Position(lat: Double, lon: Double)
case class Person( firstName: String, lastName: String, p: Option[Position] )
object Person
implicit val reader = (
(__ \ "personFirstName" ).read[String] and
(__ \ "personLastName" ).read[String] and (
(__ \ "positionLat" ).readNullable[Double] and
(__ \ "positionLon" ).readNullable[Double]
)((latOpt: Option[Double], lonOpt: Option[Double]) =>
for lat <- latOpt ; lon <- lonOpt yield Position(lat, lon)
)
)(Person.apply _)
Json.parse(jsonStr).validate[Person] // yields JsSuccess(Person(FirstName,LastName,None),)
另外,请注意,要成为有效的 JSON,您需要 quote the data keys。
【讨论】:
【参考方案2】:您的 javascript 对象应该与您的案例类的结构相匹配。 Position
还需要一个 json 阅读器。
val jsonStr = """ "personFirstName": "FirstName",
"personLastName": "LastName",
"position":
"lat": null,
"lon": null
"""
case class Person( firstName: String, lastName: String, p: Option[Position] )
object Person
implicit val reader = (
(__ \ 'personFirstName ).read[String] ~
(__ \ 'personLastName ).read[String] ~
(__ \ 'position ).readNullable[Position]
)(Person.apply _)
case class Position( val lat: Double, val lon: Double)
object Position
implicit val reader = (
(__ \ 'lat ).read[Double] ~
(__ \ 'lon ).read[Double]
)(Position.apply _)
如果Position
的任何一个字段在json对象中为空/缺失,它将被解析为None
。所以,jsonStr.as[Person] = Person("FirstName", "LastName", None)
【讨论】:
感谢您的提示,但不幸的是我无法更改 JSON 结构,这就是为什么我不知道如何解决这个问题。以上是关于Play 2.2 JSON Reads with combinators:如何处理嵌套的可选对象?的主要内容,如果未能解决你的问题,请参考以下文章
带有 Play 2.2 库的密封特征的无噪声 JSON 格式
将 Play 框架与 Scala 结合使用,如何将 Json Validation 消息人性化?
Play 2.2 动作未与 Web 服务响应处理程序并行处理
Question: Should I use reads with good quality but failed-vendor flag?--biostart for vendor quality