2011-02-10 48 views
4

有誰知道在使用最新版本的Grails JSONBuilder多次發送同一對象時避免重複封閉的方法嗎?如何消除使用JSONBuilder時的剪切和粘貼封閉

我有一個Group域對象,其中包含一組MembersLeaders。我想找到一種方法來釋放一個人而不必剪切和粘貼閉包。

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 JSONrender Group.list().encodeAsJSON,因爲我需要控制我的對象的哪些部分被編碼。

2)我會接受權威的答案,解釋爲什麼不能這樣做。

+0

你是如何「分別定義閉包?」的。 我相信def closure = {...}應該適用於你的情況... – jpertino 2011-02-10 14:04:07

+0

這就是我所嘗試的。我曾希望它會起作用,但事實並非如此。 – lambmj 2011-02-10 15:01:43

回答

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

通過設置閉包的「委託」,可以在相同的「上下文」中執行另一個閉包。 閉包不是多線程安全的(一次只有一個委託),所以如果閉包在單個類或靜態變量中共享,每次都需要克隆閉包。

這只是一個重構代碼的想法,它可能不起作用(我沒有測試它)。 如果必須動態地決定DSL中的屬性名稱或方法名稱,則可以用「setProperty」和DSL方法調用替換爲「invokeMethod」來替換賦值(=)。 (參考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') 
      } 
     } 
    } 
}