Вызов render() из вспомогательного метода фильтра в Grails

У меня есть фильтры, подобные тем, которые определены ниже. Они запускают один и тот же блок кода в разных местах, поэтому, чтобы сохранить его СУХИМ, я преобразовал этот код в метод с именем doResponse().

class MyFilters {

    def filters = {
        web(uri: '/web/**') {
            before = {

                // Do Stuff
                if (condition) {
                    doResponse(request, response, params)
                }
                return true
            }
            after = {
                if (condition) {
                    doResponse(request, response, params)
                }
                else {
                    // Do Stuff
                    doResponse(request, response, params)
                }

            }
            afterView = {
            }
        }
    }

    boolean doResponse(request, response, params) {
    // Do Stuff
        render(status: statusCode, contentType: "text/xml", encoding: "ISO-8859-1", text: text)
    // Do post-render stuff
        return false
    }
}

Однако это имеет неприятный побочный эффект. Кажется, что метод render() доступен только внутри закрытия фильтров. Есть ли какой-нибудь (аккуратный) способ вызвать render() из doResponse()?

Изменить: ошибка, которую я получаю:

groovy.lang.MissingMethodException: Нет подписи метода: MyFilters.render() применим для типов аргументов: (java.util.LinkedHashMap) значения: [[status: 500, contentType: text/xml, encoding: ISO-8859-1 , текст:...]]


person Einar    schedule 04.11.2010    source источник


Ответы (3)


Передайте объект, определяющий метод render(..), методу doRespond(..) и вызовите метод render(..) для этого объекта.

Замыкания имеют некоторые неявные переменные, включая их owner, которые относятся к родительскому замыканию; поэтому мы можем передать это:

if (condition) {
    doResponse(owner, request, response, params)
}

doRespond(..) метод:

boolean doResponse(webFilter, request, response, params) {
    // Do Stuff
    webFilter.render(status: statusCode, contentType: 
        "text/xml", encoding: "ISO-8859-1", text: text)
    // Do post-render stuff
    return false
}
person robbbert    schedule 04.11.2010
comment
привет, я пытался это сделать, но получаю: java.lang.NullPointerException: невозможно установить свойство viewName для нулевого объекта в java.lang.Thread.run(Thread.java:680) - person Arthur Neves; 30.05.2011

Не могли бы вы передать ссылку на функцию render функции doResponse?

ie:

if( condition ) {
  doResponse(request, response, params, this.&render )
}

и

boolean doResponse( request, response, params, renderFn ) {
// Do Stuff
    renderFn( status: statusCode, contentType: "text/xml", encoding: "ISO-8859-1", text: text )
// Do post-render stuff
    return false
}
person tim_yates    schedule 04.11.2010
comment
К сожалению, это эквивалентно вызову render() непосредственно из doResponse(). Я получаю ту же ошибку. - person Einar; 04.11.2010
comment
Штопать. Из интереса, не могли бы вы добавить полученную ошибку к тексту вопроса? - person tim_yates; 04.11.2010
comment
Конечно. Кажется, что SO отсекает последние части текста исключения, но этого должно быть достаточно. - person Einar; 04.11.2010
comment
Итак, когда вы попробуете код выше, вы получите ту же самую ошибку? Или он меняется на: No signature of method: MyFilters.renderFn() ? - person tim_yates; 04.11.2010
comment
Точно так же, он по-прежнему сообщает об ошибке на render(), а не на renderFn() - person Einar; 04.11.2010
comment
Вместо this.&render передайте owner.owner.&render, так как мы находимся внутри вложенного замыкания (this означает это замыкание). - person robbbert; 04.11.2010

Вы можете попробовать это решение.

Измените doResponse на закрытие:

 def doResponse = {
        render(status: statusCode, contentType: "text/xml", encoding: "ISO-8859-1", text: text)
        return false 
 }

Вызов doResponse (из закрытия фильтра):

def doResponseClosure = doResponse.clone()
doResponseClosure.delegate = delegate
// if it doesn't work, try adding: doResponseClosure.owner = owner
return doResponseClosure()

Клонирование выполняется из соображений параллелизма.

Я успешно использовал этот метод в других DSL Grails, таких как замыкания Criteria.

person Lari Hotari    schedule 05.11.2010
comment
Спасибо. Это работает, но решение robbberts требует чуть меньше кода. - person Einar; 05.11.2010