有没有人知道使用最新版本的Grails JSONBuilder多次发出同一个对象时避免重复闭包的方法?
我有一个Group
域对象,其中包含Members
和Leaders
的集合。我想找到一种方法来排出一个人而不必剪掉和粘贴封口。
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
members = array {
group.members?.person?.sort().each { Person person ->
m = { // Person closure copy #1
id = person.id
firstName = person.firstName
lastName = person.lastName
}
}
}
leaders = array {
group.leaders?.person?.sort().each { Person person ->
l = { // Person closure copy #2
id = person.id
firstName = person.firstName
lastName = person.lastName
}
}
}
}
}
}
}
我已尝试单独定义闭包,但会导致错误,例如:exception: No such property: id for class:
。
一些注意事项:
1)示例中的域对象大大简化。我正在使用JSONBuilder而不是render Group.list() as JSON
或render Group.list().encodeAsJSON
,因为我需要控制对象的哪些部分被编码。
2)我会接受权威的答案,解释为什么不能这样做。
答案 0 :(得分:3)
使用闭包反复失败后,我有一个解决方案。它不直接使用闭包,而是使用一个返回地图的闭包。
class Person {
...
def toMap = {
def map = [:]
map["id"] = this.id
map["firstName"] = this.firstName
map["lastName"] = this.lastName
return map
}
}
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
members = array {
group.members?.person?.sort().each { Person person ->
m(person.toMap())
}
}
leaders = array {
group.leaders?.person?.sort().each { Person person ->
l(person.toMap())
}
}
}
}
}
}
m(person.toMap())
语法不直观,但它有效并且允许我避免重复自己。 This blog entry提供了详细信息并解释了当前Grails JSONBuilder的来源。
答案 1 :(得分:1)
您可以通过设置闭包的“委托”在同一“上下文”中执行另一个闭包。 闭包不是多线程安全的(一次只有一个委托),因此如果闭包在单例类或静态变量中共享,则每次都必须克隆闭包。
这只是重构代码的想法,它可能不起作用(我没有测试它)。 如果必须动态决定DSL中的属性名称或方法名称,可以使用“setProperty”替换赋值(=),使用“invokeMethod”替换DSL方法调用。 (参考http://groovy.codehaus.org/api/groovy/lang/Closure.html)
def personClosure = { Person person, varname ->
setProperty(varname, {
id = person.id
firstName = person.firstName
lastName = person.lastName
})
}
def groupMembersClosure = { memberList, memberListVarName, memberVarName ->
personClosure.delegate = delegate
setProperty(memberListVarName, array {
memberList?.person?.sort().each personClosure, memberVarName
})
}
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
groupMembersClosure.delegate = delegate
groupMembersClosure(group.members, 'members', 'm')
groupMembersClosure(group.leaders, 'leaders', 'l')
}
}
}
}