2013-10-20 10 views
6

sto impazzendo cercando di analizzare tale struttura JSON in Play Framework 2.2:Riproduci 2.2 Letture JSON con i combinatori: come gestire gli oggetti opzionali nidificati?

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

ho 2 classi case:

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

Come si può vedere, posizione non è obbligatoria nel caso in persona classe.

stavo cercando di ottenere un'istanza di persona che utilizza qualcosa di simile

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

ma presto mi sono reso conto non ho idea di come trattare con l'oggetto Option[Position]: l'intenzione sarebbe quella di creare un'istanza di un Some(Position(lat,lon)) se entrambi 'lat' e 'lon' sono specificati e non null, altrimenti istanziare None.

Come gestiresti questo?

risposta

10

Sono abbastanza sicuro che c'è un modo migliore di fare ciò che vuoi rispetto a quello che sto per postare, ma è tardi e non riesco a capirlo ora. Suppongo che cambiare semplicemente la struttura JSON che stai consumando non sia un'opzione qui.

È in grado di fornire una funzione costruttore che prende due opzionali raddoppia per lat/lon e produce una posizione se sono entrambi presenti.

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

Si noti inoltre che per essere valida JSON è necessario quote the data keys.

4

L'oggetto javascript deve corrispondere alla struttura delle classi case. Position dovrà anche avere un lettore 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 _) 

} 

Se uno dei campi di Position sono nulli/incompleti nell'oggetto JSON, sarà analizzata come None. Quindi, jsonStr.as[Person] = Person("FirstName", "LastName", None)

+0

Grazie per il tuo suggerimento, ma sfortunatamente non riesco a cambiare la struttura JSON, ecco perché non ho idea di come risolverlo. – Max

Problemi correlati