2013-10-20 50 views
6

我要瘋了試圖播放框架2.2解析此JSON結構:播放2.2 JSON與組合器讀取:如何處理嵌套的可選對象?

val jsonStr = """{ personFirstName: "FirstName", 
    personLastName: "LastName" 
    positionLat: null, 
    positionLon: null }""" 

我有2個case類:

case class Position(val lat: Double, val lon: Double) 
case class Person(firstName: String, lastName: String, p: Option[Position]) 

正如你所看到的,位置是不是在人的情況下強制類。

我是想用這樣的

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

得到人的實例,但我很快就意識到我不知道如何應對Option[Position]對象:有意將實例化一個Some(Position(lat,lon))如果兩個'lat'和'lon'被指定並且不爲空,否則實例化None

你會如何處理?

回答

10

我敢肯定,做我想要發佈的內容還有更好的方式,但現在已經晚了,我現在無法弄清楚。我假設簡單地改變你正在使用的JSON結構在這裏不是一種選擇。

您可以提供一個構建器功能,該功能需要兩個可選的雙打/經緯度,併產生一個位置,如果他們都存在。

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

4

您的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字段爲null /在JSON對象丟失,它會被解析爲None。所以,jsonStr.as[Person] = Person("FirstName", "LastName", None)

+0

感謝您的提示,但不幸的是我不能改變JSON結構,這就是爲什麼我不知道如何解決這個問題。 – Max