2013-07-23 13 views
9

In Play 2.1 usiamo qualcosa come sotto per ottenere un oggetto Crea da un JSON attraverso letture.Gioca JSON Combinators

implicit val creatureReads = (
    (__ \ "name").read[String] and 
    (__ \ "isDead").read[Boolean] and 
    (__ \ "weight").read[Float] 
)(Creature.apply _) 

Essendo relativamente nuovo a Scala, sto cercando di capire se c'è qualche altro modo per costruire l'oggetto Creatura senza utilizzare il metodo apply? Sarebbe possibile avere una funzione anonima per creare l'oggetto invece di fare affidamento sulla domanda?

Ho casi di utilizzo in cui la maggior parte dei campi nei miei oggetti potrebbe mancare, ma mi piacerebbe ancora costruire l'oggetto da quello che ho. È meglio definire una sola READ per l'oggetto e usare readnullable per ciascuno dei campi?

Inoltre, potrei avere condizionali complessi, quindi sarebbe più semplice definire le funzioni personalizzate per costruirlo invece di provare a catturare tutti i casi in un Reader?

risposta

18

Sì, naturalmente, il metodo apply è solo un metodo che accetta tutti i parametri delle classi case. Questo si traduce approssimativamente al seguente:

implicit val creatureReads = (
    (__ \ "name").read[String] and 
    (__ \ "isDead").read[Boolean] and 
    (__ \ "weight").read[Float] 
)((name: String, isDead: Boolean, weight: Float) => new Creature(name, isDead, weight)) 

Per i campi mancanti si dovrebbe davvero utilizzare readNullable e avvolgere i vostri campi classi per Option. Se sono disponibili impostazioni predefinite per i campi facoltativi, è possibile utilizzare orElse(Reads.pure(value)).

Diciamo weight è opzionale e isDead è falso per impostazione predefinita:

implicit val creatureReads = (
    (__ \ "name").read[String] and 
    (__ \ "isDead").read[Boolean].orElse(Reads.pure(false)) and 
    (__ \ "weight").readNullable[Float] 
)(Creature.apply _) 

A volte non hai nemmeno voglia di leggere qualcosa da JSON. In tal caso, una possibilità è passare il valore in modo esplicito:

def creatureReads(createdAt: DateTime) = (
    (__ \ "name").read[String] and 
    (__ \ "isDead").read[Boolean].orElse(Reads.pure(false)) and 
    (__ \ "weight").readNullable[Float] and 
    (__ \ "createdAt").read(createdAt) 
)(Creature.apply _) 
+0

Grazie, che riesce per me. Ma un'altra domanda su JSErrors, quale sarebbe un modo pulito per specificare un errore personalizzato invece di "path \ foo" non è stato trovato? C'è un posto dove posso leggere? –

+0

Non per le letture predefinite, ma dipende dal caso d'uso. Puoi pubblicare una domanda separata con quella? –

+0

Certo, puoi dare un'occhiata a http://stackoverflow.com/questions/17818924/play-framework-json-reader-and-custom-jserrors –

-1

Trovo che questo sia molto più leggibile:

implicit val createReads = new Reads[Creature] { 
    override def reads(json: JsValue): JsResult[Creature] = { 
    val creature = Creature(
     name = (json \ "name").as[String], 
     isDead = (json \ "isDead").as[Boolean], 
     weight = (json \ "weight").as[Float] 
    ) 
    JsSuccess(creature) 
    } 
} 
+0

Questo non fornisce i casi 'JsError', no? O gioca automaticamente gestire le eccezioni lanciate in 'reads 'e fornire un' JsError' per quelli? – advait