2013-07-15 2 views
7

Ich möchte JSON für eine Liste produzieren, die sowohl Basisklassen als auch abgeleitete Klassen enthält. Der folgende Code erzeugt nur JSON für die Tierklasse (ich erhalte das Zuchtfeld für die Hundetypmitglieder nicht). Etwas Hilfe wäre willkommen.Scala Play Framework 2.1 abgeleitete Klassen

Scala und spielen Neueinsteiger hier, bitte entschuldigen Sie die unangemessene Verwendung der Terminologie.

Antwort

5

Die json API verwendet ausgiebig implizite Parameter, was ein Merkmal von Scala ist, wo Sie eine "implizite" Parameterliste bereitstellen können und wenn Sie diese Parameter nicht angeben, wird der Compiler versuchen, ein Objekt im aktuellen Bereich zu finden markiert als implizit und entspricht dieser Signatur.

So würde, wenn Sie zum Beispiel schreiben:

implicit val s = "my implicit string" 

def magicPrint(implicit message: String) { println(message) } 

// and then call it 
magicPrint 

Der Compiler s für den Parameter Nachricht wählen würde, da sie in ihrem Umfang und hat den richtigen Typ (String), so dass nach der impliziten Auflösung der letzten Zeile Code aussehen würde eigentlich eher wie dieses

magicPrint(s) 

Das Format/Writer vom Compiler ausgewählt wird, bei der Kompilierung mit einem impliziten Parameter. Wenn Sie sich die Signatur der Methode ansehen, toJson[A](item: A)(implicit writes: Writes[A]), dauert es eine implizite Writes[A], die in Ihrem Fall eine Writes[List[Animal]] ist, da List[Animal] der Typ Ihrer Liste l ist. Play enthält einen Standard hat einen Schreiber, der kümmert sich um die Sammlung (DefaultWrites.traversableWrites), die wiederum eine implizite Writes[A] nimmt - in Ihrem Fall Writes[Animal], so wird der Compiler auswählen und übergeben Sie Ihre AnimalWrites.

, dass Ihre Liste verschiedene Arten von Tieren enthält, ist etwas, das hat, dass von den Typinformationen zu wissen, erhältlich bei Ihren Json.toJson(l)

So keine Möglichkeit, zur Laufzeit und der Compiler geschieht, wie Sie sehen, nicht erreichen können, was Sie wollen in der Art und Weise haben Sie, aber Sie können, indem man das Tier Schriftsteller wissen über die Subtypen, zum Beispiel in fast der gleichen Weise tun:

implicit object animalWrite extends Writes[Animal] { 
    def writes(ts: Animal) = ts match { 
    // this will get an implicit Writes[Dog] since d is a Dog 
    case d: Dog => Json.toJson(d) 
    // this will get an implicit Writes[Cat] since c is a Cat 
    case c: Cat => Json.toJson(c) 
    case x => throw new RuntimeException(s"Unknown animal $x") 
    } 
} 

Hope this geholfen!

+0

Danke johanandren. Das ist hilfreich, ich dachte, das Problem hätte mit Implicits zu tun, aber ich habe nicht verstanden, wie. Was ich getan habe, um Abhilfe zu schaffen, war die Implementierung einer serialisierten Methode in Dog und Cat, die 'Json.toJson (this)' aufruft und sie mit 'l.map (_. Serialize) .mkString (" [",", ","] ")'. Deines ist besser, da du das Json nicht zusammen wie ich manuell verketten musstest. Vielen Dank. – ariscris

+0

is'nt besser eine Funktion toJson in Tier Hexe hinzufügen, dass '' ' Fall Klasse Hund umgesetzt werden könnten (außer Kraft setzen val name: String, val Rasse: String) erweitert Tier (Name) { def toJson = Json.toJson (this) } '' ' – crak

+0

In der Regel wird dies vermieden, da es Ihr Domain-Modell mit den Implementierungsdetails einer Form der Serialisierung mischen und eng koppeln würde, während Typklassen, die JSON spielen, typischerweise nette Entkopplungen verwendet Dies. – johanandren