2016-06-23 16 views
4

コンテキストスカラPlayJson循環参照

私はそうのような自体を指す階層の項目である場合クラスがある:

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

私はこのためPlayJson Formatしたいです。

通常、あなただけ行うことができます。

implicit lazy val formatter = Json.format[MyCaseClass] 

しかし、これは動作しません。

なぜですか?それが終わる、それはそれはまだ構築されていないNodeのための既存のフォーマッタを探しますフィールドchildrenになるとき

PlayJsonは、それはすべてのフィールドを通過します、ケースクラスのFormatを生成するためにScalaのマクロを使用していますコンパイルエラーで:

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

質問

これにアプローチする最良の方法は何ですか?
これはPlayJson形式のマクロの既知の問題ですか?

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)) 

ReadsWritesは対称的であるような場合には、あなたは、単一のFormatとして全体を作成することができますので、::

答えて

5

この

はプレイJSON docsrecursive typesの下で見つけることができるものです
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

賢明、ポインタありがとう! –

+1

私の編集を見て、全体が少し短くなる可能性があります。 –

+0

マクロに内部化されるべきもののようです。私はまだ自分のマクロでScalaで遊んでいません。 Scalaマクロに固有の何かがありますが、これは不可能ですか? –