将“递归”对象转换为JSON(使用Scala的Play Framework 2.4)

时间:2016-04-18 05:53:27

标签: json scala intellij-idea playframework playframework-2.0

我已经达到了我的代码编译成功的程度,但我对我的解决方案有疑问,并且因为这个原因发布了这个问题。

我将Node类定义为:

case class Node(id: Long, label: String, parent_id: Option[Long])

我引用/取消引用递归的原因是因为从技术上讲,我不在节点中存储节点。相反,每个节点都有一个指向其父节点的指针,我可以说:给我所有Node 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等...递归地

以下是节点的Writes Converter:

/** 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 JSON API为大多数基本类型提供隐式写入,例如   如Int,Double,String和Boolean。它还支持Writes for   写入[T]存在的任何类型T的集合。

我需要指出Node.getChildrenOf(node.id)从DB返回一个节点列表。所以根据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

我将“显式结果类型”添加到我的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转换器的整体方法是否可怕?

感谢并为这篇长篇文章感到抱歉。

1 个答案:

答案 0 :(得分:1)

问题在于"children" -> Node.getChildrenOf(node.id)Node.getChildrenOf(node.id)会返回List[Node]。而Json.obj中的任何属性都需要JsValueWrapper。在这种情况下,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)))
  )
}

这至少可以编译,但我没有用任何数据测试它。