[英]How to deserialize a scala tree with JSON4S
Serialization works fine but I have nothing for deserialization. 序列化工作正常,但是我不需要反序列化。 I found interesting solution for abstract class here How to serialize sealed abstract class with Json4s in Scala?
我在这里找到了抽象类的有趣解决方案。 如何在Scala中使用Json4s序列化密封的抽象类? but it doesn't deal with trees.
但它不涉及树木。
This the code of my test with a standard JSON4S : 这是我使用标准JSON4S测试的代码:
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.native.Serialization.{ read, write }
import org.json4s.native.Serialization
abstract class Tree
case class Node(nameN: String, trees: List[Tree]) extends Tree
case class Leaf(nameL: String) extends Tree
object Tree extends App {
implicit val formats = Serialization.formats(NoTypeHints)
// object creation to test the serialization
val root =
Node(
"Grand Pavois project",
List(
Node(
"studies",
List(
Leaf("preliminary studies"),
Leaf("detailled studies")
)
),
Node(
"realization",
List(
Leaf("ground"),
Leaf("building"),
Leaf("roof")
)
),
Node(
"delivery",
List(
Leaf("quality inspection"),
Leaf("customer delivery")
)
)
)
)
val serialized = write(root) // object creation and serialization
println(s"serialized: $serialized") // print the result, this is OK
// and now what about deserialization?
// string creation for deserialization
// ( it is the same as serialized above, I do like that to trace for the demo)
val rootString = """
{
"nameN": "Grand Pavois project",
"trees": [
{
"nameN": "studies",
"trees": [
{
"nameL": "preliminary studies"
},
{
"nameL": "detailled studies"
}
]
},
{
"nameN": "realization",
"trees": [
{
"nameL": "ground"
},
{
"nameL": "building"
},
{
"nameL": "roof"
}
]
},
{
"nameN": "delivery",
"trees": [
{
"nameL": "quality inspection"
},
{
"nameL": "customer delivery"
}
]
}
]
}
"""
//standard deserialization below that produce an error :
// "Parsed JSON values do not match with class constructor"
val rootFromString = read[Tree](rootString)
}
Now I guess the solution is with a custom deserializer probably a recusive one but how to define it? 现在我猜想解决方案是使用自定义解串器,可能是一种可追溯的解决方案,但是如何定义呢? That is the question.
就是那个问题。 Thanks for your help.
谢谢你的帮助。
This solution doesn't use a custom deserializer, but instead creates a type that matches both Node
and Leaf
and then converts to the appropriate type later. 此解决方案不使用自定义反序列化器,而是创建一个同时匹配
Node
和Leaf
的类型,然后在以后转换为适当的类型。
case class JsTree(nameN: Option[String], nameL: Option[String], trees: Option[List[JsTree]])
def toTree(node: JsTree): Tree = node match {
case JsTree(Some(name), None, Some(trees)) =>
Node(name, trees.map(toTree))
case JsTree(None, Some(name), None) =>
Leaf(name)
case _ =>
throw new IllegalArgumentException
}
val rootFromString = toTree(read[JsTree](rootString))
The JsTree
class will match both Node
and Leaf
values because it has option fields that match all the fields in both classes. JsTree
类将匹配Node
和Leaf
值,因为它具有与两个类中的所有字段都匹配的选项字段。 The toTree
method recursively converts the JsTree
to the appropriate Tree
subclass based on which fields are actually present. 该
toTree
方法递归转换JsTree
到适当的Tree
子类基于哪个字段是实际存在。
Here is the solution using a custom serializer: 这是使用自定义序列化程序的解决方案:
import org.json4s.JsonDSL._
class TreeSerializer extends CustomSerializer[Tree](format => ({
case obj: JObject =>
implicit val formats: Formats = format
if ((obj \ "trees") == JNothing) {
Leaf(
(obj \ "nameL").extract[String]
)
} else {
Node(
(obj \ "nameN").extract[String],
(obj \ "trees").extract[List[Tree]]
)
}
}, {
case node: Node =>
JObject("nameN" -> JString(node.nameN), "trees" -> node.trees.map(Extraction.decompose))
case leaf: Leaf =>
"nameL" -> leaf.nameL
}))
Use it like this: 像这样使用它:
implicit val formats: Formats = DefaultFormats + new TreeSerializer
read[Tree](rootString)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.