Scala PlayJson 循环引用
Scala PlayJson Cyclic Reference
上下文
我有一个案例 class,它是层次结构中的一个项目,它是这样引用自身的:
case class Node(
name: String,
children: Option[Seq[Node]] = None
)
为此我想要一个 PlayJson Format
。
通常,您可以这样做:
implicit lazy val formatter = Json.format[MyCaseClass]
但这行不通。
为什么?
PlayJson 使用 Scala 宏为案例 class 生成 Format
,它将遍历所有字段,当到达字段 children
时,它将寻找一个Node
的现有格式化程序尚未构建,以编译错误结束:
No implicit format for Option[Seq[Node]] available.
[error] implicit lazy val formatter = Json.format[Node]
问题
解决这个问题的最佳方法是什么?
这是 PlayJson 格式宏的已知问题吗?
这个东西可以在play-recursive types
下面找到-json docs:
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))
因为在那种情况下 Reads
和 Writes
是对称的,您可以将整个事物创建为单个 Format
:
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))
上下文
我有一个案例 class,它是层次结构中的一个项目,它是这样引用自身的:
case class Node(
name: String,
children: Option[Seq[Node]] = None
)
为此我想要一个 PlayJson Format
。
通常,您可以这样做:
implicit lazy val formatter = Json.format[MyCaseClass]
但这行不通。
为什么?
PlayJson 使用 Scala 宏为案例 class 生成 Format
,它将遍历所有字段,当到达字段 children
时,它将寻找一个Node
的现有格式化程序尚未构建,以编译错误结束:
No implicit format for Option[Seq[Node]] available.
[error] implicit lazy val formatter = Json.format[Node]
问题
解决这个问题的最佳方法是什么?
这是 PlayJson 格式宏的已知问题吗?
这个东西可以在play-recursive types
下面找到-json docs:
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))
因为在那种情况下 Reads
和 Writes
是对称的,您可以将整个事物创建为单个 Format
:
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))