我怎样才能为树状案例 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
我想为 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