2016-06-23 8 views
4

ContextScala PlayJson Cyclic Referenz

ich einen Fall Klasse haben, die ein Element in einer Hierarchie, die wie so auf sich selbst verweist:

case class Node(
    name:  String, 
    children: Option[Seq[Node]] = None 
) 

ich einen PlayJson Format dafür möchte.

Normalerweise können Sie einfach tun:

implicit lazy val formatter = Json.format[MyCaseClass] 

Aber das funktioniert nicht.

Warum?

PlayJson verwendet eine Scala Makro eine Format für den Fall Klasse zu produzieren, sie durch alle Felder gehen, wenn es um das Feld children wird es für einen vorhandenen Formatierer für Node aussehen wird, die es noch nicht gebaut wurde, endet mit einem Übersetzungsfehler:

No implicit format for Option[Seq[Node]] available. 
[error] implicit lazy val formatter = Json.format[Node] 

Fragen

Was ist der beste Weg, um diesen Ansatz?
Ist dies ein bekanntes Problem mit PlayJson-Format Makro?

Antwort

5

Dies ist etwas, das docs unter recursive types im Spiel-json zu finden ist: in diesem Fall

import play.api.libs.functional.syntax._ 
import play.api.libs.json.{Reads, Writes, _} 

case class Node(name: String, children: Option[Seq[Node]] = None) 

implicit lazy val nodeReads: Reads[Node] = (
    (__ \ "name").read[String] and 
    (__ \ "children").lazyReadNullable(Reads.seq[Node](nodeReads)) 
)(Node) 

implicit lazy val nodeWrites: Writes[Node] = (
    (__ \ "name").write[String] and 
    (__ \ "children").lazyWriteNullable(Writes.seq[Node](nodeWrites)) 
)(unlift(Node.unapply)) 

Da Reads und Writes symmetrisch sind, können Sie das Ganze als eine einzige Format erstellen:

implicit lazy val nodeFormat: Format[Node] = (
    (__ \ "name").format[String] and 
    (__ \ "children").lazyFormatNullable(Reads.seq[Node](nodeFormat), Writes.seq[Node](nodeFormat)) 
)(Node.apply, unlift(Node.unapply)) 
+0

Brilliant, danke für den Zeiger! –

+1

Check out my edit, das Ganze könnte ein wenig verkürzt werden. –

+0

Scheint wie etwas, das in das Makro internalisiert werden sollte. Ich habe noch nicht mit meinem eigenen Makro in Scala gespielt; Gibt es etwas Spezifisches über Scala-Makros, was bedeutet, dass dies nicht möglich ist? –

Verwandte Themen