将 "recursive" 对象转换为 JSON (Play Framework 2.4 with Scala)
Converting "recursive" object to JSON (Play Framework 2.4 with Scala)
我已经达到了我的代码可以成功编译的地步,但我对我的解决方案有疑问,因此 post 提出这个问题。
我有一个节点 class 定义为:
case class Node(id: Long, label: String, parent_id: Option[Long])
我 quote/unquote 递归的原因是因为从技术上讲,我不在节点中存储节点。相反,每个节点都有一个指向其父节点的指针,我可以说:给我节点 id=X 的所有子节点。
为了可视化,这里有一个示例树。我想给出 root_node 的 ID,并获得树对 Json 字符串的转换:
root_node
|_ node_1
| |_ node_11
| |_ node_111
|_ node_2
|_ node_3
Json 看起来像:
{"title": "root_node", "children": [...]}
子数组包含 node_1、2 和 3 等...递归地
这是节点的写入转换器:
/** json converter of Node to JSON */
implicit val NodeWrites = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
"children" -> Node.getChildrenOf(node.id)
)
}
引用 Play 文档:
The Play JSON API provides implicit Writes for most basic types, such
as Int, Double, String, and Boolean. It also supports Writes for
collections of any type T that a Writes[T] exists.
我需要指出 Node.getChildrenOf(node.id) returns 来自数据库的节点列表。所以根据 Play 的文档,我应该能够将 List[Node] 转换为 Json。好像在Writes转换器内部做这个比较麻烦
这是 运行 此代码产生的错误:
type mismatch;
found : List[models.Node]
required: play.api.libs.json.Json.JsValueWrapper
Note: implicit value NodeWrites is not applicable here because it comes after the application point and it lacks an explicit result type
我将 "explicit result type" 添加到我的 Writes 转换器中,结果如下:
/** json converter of Node to JSON */
implicit val NodeWrites: Writes[Node] = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
"children" -> Node.getChildrenOf(node.id)
)
}
代码现在可以正常执行了,我可以在浏览器上看到这棵树。
尽管这在我看来是最干净的工作解决方案,但 IntelliJ 仍然抱怨该行:
"children" -> Node.getChildrenOf(node.id)
说:
Type mismatch: found(String, List[Node]), required (String, Json.JsValueWrapper)
难道 IntelliJ 的错误报告不是基于 Scala 编译器?
最后,JSON 转换器的整体方法是否糟糕?
感谢和抱歉 post。
问题出在"children" -> Node.getChildrenOf(node.id)
。 Node.getChildrenOf(node.id)
returns一个List[Node]
。而 Json.obj
中的任何属性都需要 JsValueWrapper
s。在这种情况下 JsArray
.
像这样的东西应该可以工作:
implicit val writes = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
// Note that we have to pass this since the writes hasn't been defined just yet.
"children" -> JsArray(Node.getChildrenOf(node).map(child => Json.toJson(child)(this)))
)
}
这至少可以编译,不过我还没有用任何数据测试它。
我已经达到了我的代码可以成功编译的地步,但我对我的解决方案有疑问,因此 post 提出这个问题。
我有一个节点 class 定义为:
case class Node(id: Long, label: String, parent_id: Option[Long])
我 quote/unquote 递归的原因是因为从技术上讲,我不在节点中存储节点。相反,每个节点都有一个指向其父节点的指针,我可以说:给我节点 id=X 的所有子节点。
为了可视化,这里有一个示例树。我想给出 root_node 的 ID,并获得树对 Json 字符串的转换:
root_node
|_ node_1
| |_ node_11
| |_ node_111
|_ node_2
|_ node_3
Json 看起来像:
{"title": "root_node", "children": [...]}
子数组包含 node_1、2 和 3 等...递归地
这是节点的写入转换器:
/** json converter of Node to JSON */
implicit val NodeWrites = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
"children" -> Node.getChildrenOf(node.id)
)
}
引用 Play 文档:
The Play JSON API provides implicit Writes for most basic types, such as Int, Double, String, and Boolean. It also supports Writes for collections of any type T that a Writes[T] exists.
我需要指出 Node.getChildrenOf(node.id) returns 来自数据库的节点列表。所以根据 Play 的文档,我应该能够将 List[Node] 转换为 Json。好像在Writes转换器内部做这个比较麻烦
这是 运行 此代码产生的错误:
type mismatch;
found : List[models.Node]
required: play.api.libs.json.Json.JsValueWrapper
Note: implicit value NodeWrites is not applicable here because it comes after the application point and it lacks an explicit result type
我将 "explicit result type" 添加到我的 Writes 转换器中,结果如下:
/** json converter of Node to JSON */
implicit val NodeWrites: Writes[Node] = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
"children" -> Node.getChildrenOf(node.id)
)
}
代码现在可以正常执行了,我可以在浏览器上看到这棵树。
尽管这在我看来是最干净的工作解决方案,但 IntelliJ 仍然抱怨该行:
"children" -> Node.getChildrenOf(node.id)
说:
Type mismatch: found(String, List[Node]), required (String, Json.JsValueWrapper)
难道 IntelliJ 的错误报告不是基于 Scala 编译器?
最后,JSON 转换器的整体方法是否糟糕?
感谢和抱歉 post。
问题出在"children" -> Node.getChildrenOf(node.id)
。 Node.getChildrenOf(node.id)
returns一个List[Node]
。而 Json.obj
中的任何属性都需要 JsValueWrapper
s。在这种情况下 JsArray
.
像这样的东西应该可以工作:
implicit val writes = new Writes[Node] {
def writes(node: Node) = Json.obj(
"title" -> node.label,
// Note that we have to pass this since the writes hasn't been defined just yet.
"children" -> JsArray(Node.getChildrenOf(node).map(child => Json.toJson(child)(this)))
)
}
这至少可以编译,不过我还没有用任何数据测试它。