2016-04-18 4 views
0

Ich habe einen Punkt erreicht, wo mein Code erfolgreich kompiliert, aber ich habe Zweifel an meiner Lösung und posten diese Frage aus diesem Grund.Konvertieren von "rekursiven" Objekt in JSON (Play Framework 2.4 mit Scala)

Ich habe eine Node-Klasse wie folgt definiert:

case class Node(id: Long, label: String, parent_id: Option[Long]) 

Der Grund, warum ich zitiere/unquote rekursiv, weil technisch, ich habe keinen Knoten in einem Knoten speichern. Vielmehr hat jeder Knoten einen Zeiger auf seinen Elternknoten und ich kann sagen: Gib mir alle Kinder von Knoten-ID = X.

Hier ist ein Beispielbaum, aus Gründen der Visualisierung. Ich möchte die root_node die ID geben, und erhalten die Umwandlung des Baums zu einem JSON-String:

{"title": "root_node", "children": [...]} 

mit den Kindern Array mit node_1, 2 und 3 usw.:

root_node 
|_ node_1 
| |_ node_11 
|  |_ node_111 
|_ node_2 
|_ node_3 

Die Json aussehen würde, ... rekursiv

Hier ist der Writes Converter für Knoten:

/** json converter of Node to JSON */ 
implicit val NodeWrites = new Writes[Node] { 
    def writes(node: Node) = Json.obj(
    "title" -> node.label, 
    "children" -> Node.getChildrenOf(node.id) 
) 
} 

Zitiert Wiedergabe docs:

Die Play JSON API implizite Writes für die meisten Grundtypen, wie zum wie Int, Double, String und Boolean liefert. Es unterstützt auch Schreibvorgänge für Sammlungen beliebigen Typs T, für die ein Writes [T] existiert.

Ich muss darauf hinweisen, dass Node.getChildrenOf (node.id) eine Liste von Knoten aus der DB zurückgibt. Laut den Dokumenten von Play sollte ich in der Lage sein, einen List [Node] in Json umzuwandeln. Es scheint, dass dies innerhalb des Writes-Konverters selbst etwas mühsamer ist.

Hier wird der resultierende Fehler ist es, diesen Code ab:

type mismatch; 
found : List[models.Node] 
required: play.api.libs.json.Json.JsValueWrapper 
Note: implicit value NodeWrites is not applicable here because it comes after the application point and it lacks an explicit result type 

ich den „expliziten Ergebnistyp“ zu meinem Writes-Wandler, hier hinzugefügt ist das Ergebnis:

/** json converter of Node to JSON */ 
implicit val NodeWrites: Writes[Node] = new Writes[Node] { 
    def writes(node: Node) = Json.obj(
    "title" -> node.label, 
    "children" -> Node.getChildrenOf(node.id) 
) 
} 

Der Code jetzt führt richtig, ich kann den Baum im Browser visualisieren.

Auch wenn dies wie die sauberste Arbeitslösung sieht für mich, IntelliJ klagt immer noch über die Linie:

"children" -> Node.getChildrenOf(node.id) 

sagen:

Type mismatch: found(String, List[Node]), required (String, Json.JsValueWrapper) 

Könnte es sein, dass IntelliJ die Fehlerberichterstattung basiert nicht ausgeschaltet ist des Scala-Compilers?

Schließlich ist der Gesamtansatz des JSON-Konverters schrecklich?

Danke und Entschuldigung für die lange Post.

Antwort

1

Das Problem liegt in "children" -> Node.getChildrenOf(node.id). Node.getChildrenOf(node.id) gibt List[Node] zurück.Wohingegen jedes Attribut in Json.objJsValueWrapper s erwartet. In diesem Fall eine JsArray.

So etwas sollte funktionieren:

implicit val writes = new Writes[Node] { 
    def writes(node: Node) = Json.obj(
    "title" -> node.label, 
    // Note that we have to pass this since the writes hasn't been defined just yet. 
    "children" -> JsArray(Node.getChildrenOf(node).map(child => Json.toJson(child)(this))) 
) 
} 

Die zumindest compiliert, ich habe es nicht mit einem beliebigen Datum obwohl getestet.

+0

Das hat es behoben! Würdest du bitte erklären, was "(this)" tut? Ich habe versucht, es zu entfernen und es funktioniert immer noch. – Khorkhe

+0

Wenn Sie sich die Definition von ['Json.toJson'] ansehen (https://www.playframework.com/documentation/2.5.x/api/scala/index.html#play.api.libs.json. Json $), Sie werden bemerken, dass diese Funktion einen zusätzlichen impliziten Parameter hat. Normalerweise wird dieser Parameter vom Compiler ausgefüllt. Es stellt der 'toJson'-Funktion eine Implementierung zur Verfügung, um den ersten Parameter in ein Json-Objekt zu konvertieren. Ich habe es einmal mit play 2.3.10 ausprobiert, und es schien nicht zu kompilieren, ohne den '(this)' Zusatz. Falls es in Ihrem Fall funktioniert, würde ich es einfach weglassen. – irundaia

Verwandte Themen