Как исключить замыкания и вставки при использовании JSONBuilder - PullRequest
4 голосов
/ 10 февраля 2011

Кто-нибудь знает способ избежать повторения замыкания при испускании одного и того же объекта более одного раза, используя последнюю версию 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) Я приму авторитетные ответы, объясняющие, почему этого нельзя сделать.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2011

После повторных сбоев с использованием замыканий у меня есть решение.Он не использует замыкание напрямую, а вместо этого использует замыкание, которое возвращает карту.

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()) не интуитивен, но работает и позволяет мне не повторяться Эта запись в блоге содержит подробности и объясняет происхождение текущего JSONBuilder Grails.

1 голос
/ 10 февраля 2011

Вы можете выполнить другое замыкание в том же «контексте», установив «делегат» для замыкания. Замыкания не являются многопоточными (только один делегат за раз), поэтому вам придется каждый раз клонировать замыкание, если замыкания совместно используются в одноэлементном классе или статической переменной.

Это просто идея рефакторинга кода, он может не работать (я не тестировал его). Вы можете заменить присвоение (=) на «setProperty», а вызовы метода DSL на «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')
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...