我怎样才能为树状案例 class 制作编组器?

How can i make marshaller for tree-like case class?

我想为 case class 创建编组器,其中的字段引用相同 class。

case class TreeNode (name: String, parentNode: Option[TreeNode])

如果我制作序列化器

implicit val nodeJson = jsonFormat2(TreeNode)

我得到一个错误,没有找到参数 Option[TreeNode] 的隐含项 除了从头开始编写序列化之外,还有什么办法可以解决这个问题吗?

PS 我用编码器做了更多尝试

private def toNode (node: TreeNode): Map[String, Any] = {
    val parent = node.parentNode.map(toNode).orNull
    Map[String, Any] ("name" -> node.name, "parentNode" -> parent)
  }

implicit val treeNodeEncoder: Encoder[TreeNode] =
  Encoder.forProduct2("name", "parentNode")(n =>
    (n.name, n.parentNode.map(toNode).orNull)
  )

它也不起作用,因为 Map[String, Any] 也没有隐含的

假设您正在尝试使用 circe 进行这项工作,这里是一个有效的示例:


import io.circe.{Encoder,Decoder}
import io.circe.generic.semiauto.{deriveEncoder,deriveDecoder}
import io.circe.syntax._

final case class TreeNode (name: String, parentNode: Option[TreeNode])

object TreeNode {
  implicit val encoder: Encoder[TreeNode] = deriveEncoder
  implicit val decoder: Decoder[TreeNode] = deriveDecoder
}

val a = TreeNode("a", None)
val b = TreeNode("b", Some(a))
val c = TreeNode("c", Some(b))

println(c.asJson)

输出

{
  "name" : "c",
  "parentNode" : {
    "name" : "b",
    "parentNode" : {
      "name" : "a",
      "parentNode" : null
    }
  }
}

另请注意,从叶子而不是根开始表示树是不寻常的。

感谢大家的帮助,只是我发现的另一种方法可以完成,如果需要如何手动制作

implicit val treeNodeEncoder: Encoder[TreeNode] = new Encoder[TreeNode] {
    def apply(a: TreeNode): Json = {
      val list = List(
        ("name" -> Json.fromString(a.name)),
        ("parentNode" -> a.parentNode.map(this.apply).orNull),
      ).filterNot(_._2 == null)

      Json.obj(list: _*)
    }
  }

这样我们就可以避免将parentNode写成null,如果是None

就跳过它

circe 支持开箱即用,您只需要使用库提供的 semiautomatic / automatic derivation 机制即可。
您还可以修改要用于控制标识的打印机以及是否要包含 nulls

看看这段代码:

import io.circe.{Decoder, Encoder, Printer, parser}
import io.circe.syntax._
import io.circe.generic.semiauto._

final case class TreeNode(name: String, parentNode: Option[TreeNode] = None)
object TreeNode {
  implicit final val decoder: Decoder[TreeNode] = deriveDecoder
  implicit final val encoder: Encoder[TreeNode] = deriveEncoder
}

val data = TreeNode(name = "child", parentNode = Some(TreeNode(name = "parent")))

val printer = Printer.spaces2SortKeys.copy(dropNullValues = true)
val json = printer.print(data.asJson)
println(json)

println("------------------")

val result = parser.decode[TreeNode](json)
println(result)

可以看到运行here