Grails: problema com uso de herança nos Controllers

Ao fazer uma revisão na performance de uma aplicação Grails, acabei me deparando com um problema muito esquisito.

Nesta aplicação, há alguns controllers que possuíam alguns métodos comuns. Então, nada mais natural do que criar um controller pai, abstrato, do qual os demais controllers herdavam para poderem utilizar os métodos comuns. Não eram actions, eram métodos simples.

Percebi, então, que os alguns dos métodos do controller pai eram executados mesmo sem serem chamados. É isso mesmo. Não me perguntem como, mas estava acontecendo. Será que havia algum erro da minha aplicação. Pode ser que sim, mas....

Então criei uma action de teste simples no meu controller filho:

class FilhoController extends PaiController {
    def teste = {
     render "ola"
    }
}

Ou seja, nada deveria ser executado além de aparecer um "ola" na tela. Mas o problema é que ao configurar o Grails para fazer o log das queries SQL (no DataSource.groovy coloquei loggingSql = true), quando eu acessava esta action http://localhost:8080/app/filho/teste , um monte de SQL aparecia no console. Eram as queries que existiam nos métodos do PaiController. E aí? Fiquei horas, literalmente, tentando entender. Achei que fosse algo em algum Filter, algo no BootStrap, no resources.groovy, sei lá aonde. Mas não imaginei que era a herança que estava causando isso.

Bom, resolvi arriscar e acabei com a herança. Matei o "extends PaiController". Aí criei uma classe groovy comum contendo todos os métodos da antiga classe PaiController. Problema resolvido. Acredita nisso? Nem eu. Mas........

Só mais um detalhe: nesta classe groovy, que chamei de WebHelper, eu precisava de session, de um service, do request, da taglib para poder usar o método message(), e por aí vai. Então, criei esta classe com.minhaapp.web.WebHelper na pasta src/groovy, e configurei o resources.groovy para poder injetar nestas minha classe tudo que eu precisava, da seguinte forma:

beans = {
    
  webHelper(com.minhaapp.web.WebHelper) { bean ->
    bean.scope = 'prototype' // aqui pode ser singleton se vc preferir
    bean.autowire = 'byName'
    applicationTagLib = ref('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib')
  }

}


E a classe WebHelper então ficou assim:

package com.minhaapp.web


import org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib
import org.springframework.web.servlet.support.RequestContextUtils
import org.springframework.web.context.request.RequestContextHolder

public class WebHelper {
    def grailsApplication
    def meuService
    def applicationTagLib
    
    def teste(){
        println grailsApplication.class
        println RequestContextHolder.currentRequestAttributes().session.class
        println applicationTagLib.class
        println meuService.class
    }
    
}


Abcs a todos.

1 comentários:

Wanderson Santos 18 de novembro de 2010 18:25

Felipe,

Uma abordagem é injetar helper methods nos controllers. Basta utilizar o seguinte código abaixo dentro do init do seu bootstrap...

grailsApplication.controllerClasses.each { controllerClass -> controllerClass.metaClass.novoMetodo = { println 'novo método chamado!' }

PS.: É preciso injetar o grailsApplication na classe Bootstrap (def grailsApplication)

Bons códigos!