Grails / JSON:JSON #registerObjectMarshaller的递归数据结构

时间:2014-09-09 11:10:19

标签: json grails recursion data-structures groovy

我有以下自引用(递归)类:

class Node {

 String label
 // other attributes go here
 static belongsTo = [parent: Node]
 static hasMany = [children: Node]

 static constraints = {
    label blank: false
    parent nullable: true
    children nullable: true
 }
}

我在BootStrap.groovy中使用了一个marshaller,因为我只想将一些select属性发送到客户端,在这个阶段只有标签:

JSON.registerObjectMarshaller(Node) { Node node ->
    return [label: node.label, items: node.children]
}

创建节点层次结构,例如:

def parent1 = new Node(label: "Node 1").save(flush: true)
parent1.addToChildren(new Node(label: "Node 1.1"))

def parent2 = new Node(label: "Node 2").save(flush: true)
def child21 = new Node(label: "Node 2.1")
child21.addToChildren(new Node(label: "Node 2.1.1"))
parent2.addToChildren(child21)

并将其列为:

def index(Integer max) {
  params.max = Math.min(max ?: 10, 100)

  respond Node.list(params), model: [nodeInstanceCount: Node.count()]
}

我想要这样的东西:

Node 1
  |
  -- Node 1.1
Node 2
  |
  -- Node 2.1
        |
        -- Node 2.1.1

结果看起来很有希望,但有一些节点太多了:

Node 1
  |
  -- Node 1.1
Node 2
  |
  -- Node 2.1
        |
        -- Node 2.1.1
Node 1.1
Node 2.1
   |
   -- Node 2.1.1
Node 2.1.1

输出是不受欢迎的,但有意义:对于每个节点,都会调用此方法,因此需要额外的层次结构/单个节点。

我尝试解决此问题的一种方法是添加一个“处理过的”#39;属性进入Node类。这具有期望的效果(每个节点仅处理一次导致所需的层次结构)但是引入了此后必须管理该状态变量的问题。因此,我想避免这种黑客攻击。 另一种方法是让客户处理收到的数据

有没有一种简单的方法可以解决这个问题?

1 个答案:

答案 0 :(得分:1)

在发布上述问题后,我找到了罪魁祸首。我希望有一天能帮到某人,以防他们遇到类似的问题。

当我们想要的只是顶级节点时,

Node#list显然会返回所有节点:

respond Node.list(params), model: [nodeInstanceCount: Node.count()]

直接跳到答案,以下解决了这个问题:

  • 向Node
  • 添加isRoot属性

然后将index()更改为以下内容:

respond Node.findAllByIsRoot(true), model: [nodeInstanceCount: Node.count()]

提供更多详情:

  • marshaller用于将此数据转换为所需的JSON格式(由#respond方法决定,例如,查看ACCEPTCONTENT-TYPE标头,或者就像在这种情况下查看请求URI中的format字段(如UrlMappings#mappings中所定义))将是

    类型

    org.codehaus.groovy.grails.web.converters.marshaller.json.CollectionMarshaller

    因此对于列表中的每个对象,marshaller都会被调用

  • 收集编组然后委托给伴随的转换器,在我们的例子中是

    类型

    <强> grails.converters.JSON

  • JSON#value方法中,当我们注册我们的编组时,它最终会调用BootStrap.groovy类中定义的闭包