5

语境

我有一个案例类,它是层次结构中的一个项目,它像这样引用自身:

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

我想要一个 PlayJson Format

通常,您可以这样做:

implicit lazy val formatter = Json.format[MyCaseClass]

但这不起作用。

为什么?

PlayJson 使用 Scala 宏Format为案例类生成一个,它将遍历所有字段,当它到达该字段children时,它将查找Node尚未为其构建的现有格式化程序,并以编译错误结束:

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

问题

解决这个问题的最佳方法是什么?
这是 PlayJson 格式宏的已知问题吗?

4

1 回答 1

6

这可以recursive types在 play-json文档中找到:

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))
于 2016-06-23T13:06:32.583 回答