2013-10-20 2 views
6

Ich werde verrückt versuchen, diese JSON Struktur im Play-Framework zu analysieren 2.2:Abspielen 2.2 JSON Liest mit Kombinatoren: Wie geht man mit geschachtelten optionalen Objekten um?

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

I 2 Fallklassen haben:

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

Wie Sie sehen können, ist Position obligatorisch nicht in Person Fall Klasse.

Ich habe versucht, eine Instanz von Person mit so etwas wie diese

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

zu bekommen, aber ich erkennen bald, ich habe keine Ahnung, wie man mit dem Option[Position] Objekt behandeln: die Absicht, ein Some(Position(lat,lon)) wenn beide zu instanziiert wäre 'lat' und 'lon' sind angegeben und nicht null, andernfalls instanziieren Sie None.

Wie würden Sie damit umgehen?

Antwort

10

Ich bin mir ziemlich sicher, dass es einen besseren Weg gibt, zu tun, was Sie wollen, als das, was ich posten werde, aber es ist spät und ich kann es jetzt nicht herausfinden. Ich gehe davon aus, dass das Ändern der JSON-Struktur, die Sie gerade verwenden, keine Option ist.

Sie können eine Builder-Funktion liefern, die zwei optionale Doubles für lat/lon liefert und eine Position ergibt, wenn beide vorhanden sind.

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),) 

Beachten Sie auch, dass gültige JSON Sie quote the data keys sein müssen.

4

Ihr JavaScript-Objekt sollte mit der Struktur Ihrer Fallklassen übereinstimmen. Position muss auch einen JSON-Leser haben.

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 _) 

} 

Wenn eines der Felder von Position null sind/fehlt im JSON-Objekt, wird es als None analysiert werden. Also, jsonStr.as[Person] = Person("FirstName", "LastName", None)

+0

Danke für Ihren Tipp, aber leider kann ich die JSON-Struktur nicht ändern, deshalb habe ich keine Ahnung, wie ich das lösen soll. – Max

Verwandte Themen