上下文
我有一个案例类,它是层次结构中的一个项目,它引用自己是这样的:
case class Node( name: String,children: Option[Seq[Node]] = None )
我想要一个PlayJson Format
.
通常,您可以这样做:
implicit lazy val formatter = Json.format[MyCaseClass]
但这不起作用.
为什么?
PlayJson使用Scala宏为case类生成一个Format,它将遍历所有字段,当它到达字段child时,它将查找尚未构造的Node的现有格式化程序,以编译错误结束:
No implicit format for Option[Seq[Node]] available. [error] implicit lazy val formatter = Json.format[Node]
问题
解决方法
这是可以在play-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是对称的,所以您可以将整个事物创建为单个格式:
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))