2013-10-26 14 views
6

Sto tentando di elaborare una richiesta POST Ajax in Play Framework 2.1.3. I dati post è un oggetto JSON e ha una struttura ad albero simile:Leggere la struttura dell'albero JSON in Scala Play Framework

{ id: "a", name: "myname", kids : [{ id: "a1", name : "kid1", kids: []}, {id: "a2", name: "kid2", kids: [{id: "aa1", name :"grandkid", kids: []}]}] 

vorrei nido dei 'bambini' arbitrariamente profondo. La classe avrei in mente è come questo (mi rendo conto della ricorsività può essere problematico):

case class Person { 
    id: String, 
    name: String, 
    kids: Array[Person] 
} 

Il formato avrei in mente:

implicit val personFormat:Format[Person] = Json.format[Person] 

gioco sta gettando errori sul mio formato Ho scritto:

disallineamento di tipo; trovato: controller.Resources.Person richiesto: Array [controllers.Resources.Person]

Sono consapevole che Play ha una struttura ad albero. Non sono riuscito a trovare esempi/documentazione su come legarlo alle letture JSON.

Qualsiasi aiuto è molto apprezzato, grazie

risposta

9

Avrete bisogno di una val ricorsivo, qualcosa di simile:

implicit val jsonReads: Reads[Person] = ((__ \ "id").read[String] and (__ \ "name").read[String] and (__ \ "kids").read[Seq[Person]])(apply _) 

(ho cambiato il tipo di raccolta da Array per Seq, perché è più generale e permette di cambiare l'implementazione senza influire downline codice.)

Si sta utilizzando la sintassi documentata here.

+0

Grazie Robin, sto cercando di incorporare la tua risposta e ottengo un errore di compilazione 'non trovato: valore applicato'. Mi manca qualcosa di base? E i "bambini" nella classe Persona devono essere "Seq [Person]" per la tua risposta? Grazie! – Joost

+0

Oh, suppongo che tu non lo dichiari nell'oggetto compagno allora. Quindi cambia 'applica' a' Persona'. Puoi cambiarlo in 'Array' ma non sono sicuro che Play possa leggere automaticamente' Array's; è per questo che ho suggerito di cambiare il tipo di collezione usato in 'Person' da' Array' a 'Seq'. Scusa se non era chiaro. –

2

L'unico modo che vedo questo lavoro sta usando sia JsArray o Array [String] invece di Array [Person] nella classe caso Person. JSON Macro Inception è in grado di generare solo codice reads + write per primitive e liste, mappe e array per oggetti per i quali esiste già un codice JSON di lettura + scrittura implicito. Essenzialmente non puoi avere una case case che si riferisca a se stessa.

package models 

import play.api.libs.json._ 

case class Person(
    id : String, 
    name : String, 
    kids : JsArray 
) 

object Person extends ((String,String,JsArray) => Person) { 

    implicit val jsonFormat = Json.format[Person] 

} 
+1

Questo non è un buon design; che sta esponendo la rappresentazione del filo; cosa succede se decidi di accettare anche XML? –

+1

La domanda era come leggere una struttura JSON, XML è irrilevante. –

+1

Sto parlando di una possibile futura decisione di progettazione. Ma anche a prescindere da ciò, non dovresti esporre la rappresentazione del wire nelle tue case classes - forza il codice del client a preoccuparsi della deserializzazione, che non dovrebbe preoccuparsi. –