使用组合器播放2.2 JSON读取:如何处理嵌套的可选对象?

Max*_*Max 6 json scala playframework scala-2.10 playframework-2.2

我在疯狂尝试解析Play Framework 2.2中的这个JSON结构:

val jsonStr = """{ personFirstName: "FirstName",
  personLastName: "LastName"
  positionLat: null,
  positionLon: null }"""
Run Code Online (Sandbox Code Playgroud)

我有2个案例类:

case class Position( val lat: Double, val lon: Double)
case class Person( firstName: String, lastName: String, p: Option[Position] )
Run Code Online (Sandbox Code Playgroud)

如您所见,在Person案例类中,Position不是强制性的.

我试图用这样的东西得到一个Person的实例

implicit val reader = (
  (__ \ 'personFirstName ).read[String] ~
  (__ \ 'personLastName ).read[String] ~
  ( (__ \ 'positionLat ).read[Double] ~
    (__ \ 'positionLon ).read[Double] )(Position)
)(Person)
Run Code Online (Sandbox Code Playgroud)

但我很快意识到我不知道如何处理该Option[Position]对象:Some(Position(lat,lon))如果指定'lat'和'lon'并且不是null,则意图是实例化,否则实例化None.

你会怎么处理?

Mik*_*ame 10

我很确定有一种更好的方式来做你想做的事情而不是我要发布的内容,但它已经很晚了,我现在无法理解.我假设只是改变您正在使用的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),)
Run Code Online (Sandbox Code Playgroud)

另请注意,要成为有效的JSON,您需要引用数据键.