Category Archives: Grails: guia rápido e indireto

Groovy e seus mutantes: terceira parte do Guia Groovy/Grails em vídeo

Continuando a minha série sobre vídeos, é hora de nos aprofundarmos nos aspectos mutantes do Groovy. Ao menos os mais fundamentais para que a sua compreensão do Grails seja a melhor possível.

Os seguintes tópicos foram abordados:

  • Closures: que droga é esta?
  • Executando funções e acessando propriedades de forma dinâmica
  • Como modificar nossas classes em tempo de execução
  • E pra finalizar, como fazer um mexidão de classes usando mixins

Espero que gostem deste vídeo o mesmo tanto que eu gostei de fazê-lo. Ele marca uma mudança radical no material que pretendo publicar daqui pra frente.

Para acessar os vídeos restantes, use este link.

Guia Grails em Vídeo > Groovy: o “Java” que sempre quis – Aula 02

Como prometido, o vídeo da semana, entitulado “Groovy: o ‘Java’ que sempre quis’. Este e os próxmos vídeos serão focados não no Grails, mas no componente que o torna tão produtivo: a linguagem de programação Groovy.

AVISO

Um dos maiores equívocos cometidos por iniciantes em Grails (erro este que costuma inclusive destruir projetos) é programar em Groovy exatamente como seria feito com Java tradicional. Funciona? Sim, mas você cairá nos seguintes problemas:

  • Sua performance pode ser inferior – afinal de contas, você não está programando “à moda Groovy” e, consequentemente, o compilador pode deixar de executar uma série de otimizações no seu código.
  • Sua compreensão do framework será menor: Grails tira proveito de cada aspecto imaginável do Groovy. Muitas vezes, o “pensamento Java” irá te impedir de compreender o quê de fato está acontecendo por trás dos panos.
  • Sua produtividade vai ser bem menor: só pra lembrar, o objetivo por trás do Groovy é justamente prover maior produtividade aos desenvolvedores Java.

Neste vídeo, os seguintes assuntos foram tratados

  • O que é Groovy – (99% de chance de você já saber :) )
  • Como instalar – (opcional se você só vai trabalhar com Grails)
  • Principais diferenças sintáticas em relação ao Java
  • Melhorias no tratamento de strings e números
  • O que vêm a ser a tal tipagem dinâmica?

    Segue o vídeo: espero que gostem :)

    Curso itexto de Grails: Aula 1

    Acabo de publicar o segundo vídeo da série sobre Grails que pretendo publicar nos próximos meses. A idéia do primeiro vídeo é mostrar a construção do ambiente de desenvolvimento que será usado no transcorrer do curso. Para quem já viu o vídeo anterior, não há muita novidade, mas há algumas bastante importantes:

    • Foi inaugurada a página “Grails: um guia em vídeo“, aonde pretendo postar todos os vídeos que eu venha a publicar sobre o assunto. Vai ser massa, porque assim fica mais fácil assisti-los em sequência.
    • Todo o material do curso é publicado no GitHub neste repositório.

    Neste vídeo os seguintes assuntos foram tratados:

    • Instalação do Grails: executo o processo no Windows 7 (mas no repositório há um texto explicando como proceder caso você seja um usuário Linux ou Mac)
    • É apresentada a aplicação base: um gerenciador de estoque. É um exemplo suficientemente complexo para que eu possa em aulas posteriores me aprofundar (e BEM) nas entranhas do Grails
    • Inicio o desenvolvimento básico do projeto implementando as classes de domínio e criando o CRUD básico via scaffolding dinâmico. Neste processo, daremos uma pincelada em cima dos seguintes tópicos:
      • A estrutura básica de diretórios
      • Classes de domínio: definição de atributos e constraints
      • Scaffolding dinâmico
      • Configuração do acesso a dados
    • Finalmente, é gerado o pacote que pode ser instalado em praticamente todos os servidores de aplicação Java EE do mercado.

    Sem mais demora, segue o vídeo:

    O assunto do próximo vídeo será a linguagem Groovy e as principais diferenças desta em relação ao Java. Meu objetivo é mostrar uma série de armadilhas que podem ser evitadas pelos iniciantes e mais algumas técnicas que ajudam demais a incrementar nossa produtividade.

    Espero que gostem. :)

    Grails: aspectos interessantes na configuração de acesso a dados

    Em diversas aplicações que trabalhei, o único arquivo de configuração que precisamos alterar é o DataSources.groovy. E sabe o que é mais interessante neste componente do framework? É um arquivo de configuração vivo!

    Grails sempre me surpreende, até em sua configuração básica. Porém, antes de mostrar alguns aspectos pouco conhecidos deste arquivo, vou começar pelo básico.

    DataSource.groovy: o básico

    Localizado em seu projeto Grails no diretório grails-app/conf, este é o arquivo aonde devemos incluir as informações que precisaremos para que possamos acessar a base de dados aonde nossas classes de domínio serão persistidas.

    Normalmente o arquivo é composto por três seções: dataSource, hibernate e environments. No momento em que criamos uma aplicação Grails com o comando grails-app, este arquivo é gerado com a aparência abaixo:

    
    dataSource {
        pooled = true
        driverClassName = "org.hsqldb.jdbcDriver"
        username = "sa"
        password = ""
    }
    hibernate {
        cache.use_second_level_cache = true
        cache.use_query_cache = true
        cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    }
    // environment specific settings
    environments {
        development {
            dataSource {
                dbCreate = "create-drop" // one of 'create', 'create-drop','update'
                url = "jdbc:hsqldb:mem:devDB"
            }
        }
        test {
            dataSource {
                dbCreate = "update"
                url = "jdbc:hsqldb:mem:testDb"
            }
        }
        production {
            dataSource {
                dbCreate = "update"
                url = "jdbc:hsqldb:file:prodDb;shutdown=true"
            }
        }
    }
    

    Como pode ser visto, cada uma das seções que mencionei compreende um bloco de código, cuja utilidade básica de cada uma, a grosso modo, é a seguinte:

    • dataSource – Armazena as configurações que são comuns a todos os ambientes de execução (falarei mais sobre os ambientes de execução neste post)
    • hibernate – Contém informações específicas do Hibernate, como por exemplo se desejamos trabalhar com cache, expor comandos SQL, etc. Todas as configurações do Hibernate, que você normalmente incluiria no arquivo hibernate.cfg (ou no Spring) deste ORM entram neste bloco.
    • environments – Uma aplicação Grails comporta o conceito de ambientes de execução. No contexto deste arquivo, um ambiente representa uma configuração específica de acesso ao banco de dados. Por default, temos três ambientes: desenvolvimento (development), testes (test) e produção (production).

    Como assim ambientes?

    Como mencionei, Grails implementa o conceito de ambientes de execução. É comum que no ciclo de vida de uma aplicação esta possua três tipos de ambiente: aquele no qual a desenvolvemos (development), aquele no qual executamos nossos testes automatizados (test) e, finalmente aquele que realmente importa, que é o ambiente de produção (production).

    Na realidade, como já escrevi neste blog anteriormente, podemos inclusive ter mais de três ambientes. É uma maneira interessante de se ter por exemplo uma base de dados apenas para a execução de testes, o que facilita demais a vida do desenvolvedor.

    O mais interessante é que os ambientes de execução vão além da “mera” configuração de datasources. Você pode, por exemplo, criar um ambiente de execução adicional que encapsule lógica específica de um cliente seu (se sua empresa trabalha com o desenvolvimento de produtos, fica ai minha dica pra você ;) ).

    Reaproveitando código – dataSource

    A seção DataSource normalmente é mal compreendida por diversos iniciantes. A grosso modo, no entanto, esta é a parte da sua configuração que você deve usar para incluir os aspectos que serão comuns a todos os seus ambientes. Por exemplo: se todos usarem o MySQL como banco de dados, não é necessário redigitar estes dados em cada um dos ambientes, basta inserir estas configurações nesta seção, tal como no exemplo abaixo:

    dataSource {
        pooled = true
        driverClassName = "com.mysql.jdbc.Driver"
    }
    hibernate {
        cache.use_second_level_cache = true
        cache.use_query_cache = true
        cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    }
    // environment specific settings
    environments {
        development {
            dataSource {
                url = "jdbc:mysql://mysql/desenvolvimento"
                username = "jacob"
                password = "lost"
            }
        }
        test {
            dataSource {
                url = "jdbc:mysql://mysql/tests"
                username = "Benjamin"
                password = "Linus"
            }
        }
        production {
            dataSource {
                 url = "jdbc:mysql://mysql/production"
                 username = "Jack"
                 password = "Shephard"
            }
        }
    }
    

    E o dbCreate? (LEIA COM ATENÇÃO!)

    A propriedade dbCreate é uma das mais úteis e perigosas do Grails. Nós a usamos para hibernate.hbm2ddl.auto, e pode receber os seguintes valores:

    • create – Cria toda a estrutura de banco de dados pra você no momento em que a aplicação for iniciada, e também apaga todos os dados contidos nas tabelas caso estas já existam.
    • create-drop – Funciona da mesma maneira que create. A diferença é que quando a aplicação é finalizada, todas as tabelas são destruídas.
    • update – Atualiza as tabelas do banco de dados. Caso estas não existam, são criadas. Se novos atributos forem incluídos em suas classes, estes serão refletidos em suas tabelas também. No entanto, algumas mudanças não serão efetuadas. Se você por exemplo tiver renomeado campos, por exemplo, o GORM não saberá como lidar com isto (não ocorrerão erros). É importante notar também que caso atributos sejam excluídos de suas classes de domínio, isto não implicará na remoção de campos nas tabelas relacionadas (ainda bem!).
    • validate – simplesmente verifica se as suas classes de domínio estão de acordo com as tabelas do banco de dados. Nenhuma alteração é feita no banco de dados.

    Por medida de segurança, no ambiente de produção você deve simplesmente excluir esta propriedade. Assim não correrá o risco de acidentalmente apagar ou modificar uma estrutura de dados que já esteja sendo usada por seus usuários.

    Agora, o aspecto “vivo” da configuração

    Já reparou que o arquivo “DataSource.groovy” possui a extensão “.groovy”? Ao contrário da maior parte dos arquivos de configuração, algumas das configurações do Grails são na realidade scripts!

    Sendo assim, caso seja necessário, você pode definir o funcionamento do seu ambiente não apenas declarativamente, mas também lógicamente. Este aspecto pode nos mostrar uma nova gama de possibilidades, como por exemplo configurar o seu sistema de acordo com variações do ambiente no qual este se encontra instalado.

    Confuso? Então aqui segue um exemplo: suponha que você desenvolva produtos, e que não sabe de antemão qual a url de conexão com o banco de dados. Nesta nossa situação hipotética, a string de conexão com o banco de dados poderia ser uma variável de ambiente. Como você faria?

    Bem, aqui segue um exemplo:

    ...
    environments {
            ...
             production {
                 url = System.getProperty("url_de_conexao_com_o_banco_de_dados")
             }
            ...
    }
    

    Na realidade, você pode incluir qualquer código groovy dentro do seu arquivo de configuração. Sendo assim, você poderia ter algo como o código abaixo também.

    ...
    environments {
            ...
             production {
                 def valor = null
                 switch (System.getProperty("propriedade_qualquer") {
                      case "a": valor = "coisas da vida"
                      case "b": valor = "coisas da vida louca"
                 }
                 url = valor
                 new pacote.qualquer.ClasseQualquer.executeMetodo()
             }
            ...
    }
    
    

    Como pode ser visto no exemplo, você pode inclusive, apesar de não ser recomendado, executar código de inicialização presente em outras classes dentro do seu ambiente de execução. De qualquer maneira, o simples fato de ser possível incluir lógica em um arquivo de configuração já é uma vantagem fascinante.

    Um aspecto interessante a ser levado em consideração é que o DataSource.groovy é executado sequencialmente. Sendo assim, em uma configuração padrão, a seção dataSource é executada primeiro, para logo em seguida virem hibernate e environments. Mas sabe de uma coisa? Seu script pode também ser incluído FORA destes blocos e, ainda mais interessante: a ordem em que são declarados não faz diferença alguma.

    Como uso JNDI?

    A melhor opção, ao menos na minha opinião é, ao invés de incluir suas configurações de acesso ao BD no DataSources.groovy, usar o JNDI. Assim você transfere a responsabilidade pela configuração do pool e outros aspectos do acesso ao banco de dados para o responsável pela manutenção do seu servidor de aplicações. Além disto, também evita de ficar incluindo senhas e nomes de usuários em um arquivo que qualquer um possa ver. Nestes casos, usamos a propriedade jndiName, tal como no exemplo abaixo:

    ...
       production {
              jndiName = "meu_nome_jndi"
       }
    ...
    

    É possível ter apenas um ambiente?

    Para finalizar este post, uma possibilidade interessante, mas que, em minha opinião, deve ser evitada a qualquer custo. Suponha que por alguma “razão” sinistra, você não queira ter três ambientes distintos, mas apenas um. Como você faria?

    Simples: como mencionei anteriormente, a seção dataSource contém o código que será reaproveitado por todos os seus ambientes, certo? Neste caso, basta excluir a seção enrivonments e incluir toda a sua configuração de acesso nesta seção, tal como no exemplo abaixo:

    
    hibernate {
        cache.use_second_level_cache = true
        cache.use_query_cache = true
        cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    }
    dataSource {
        pooled = true
        driverClassName = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://souLouco/mesmo"
        username = "maluco"
        password = "meio_burro_também"
    }
    

    Como pode ver, é possível, mas por favor, não faça isto ok?

    Concluindo

    Como diria o tio do Homem-Aranha, “com grandes poderes, vêm grandes responsabilidades”. É exatamente o que ocorre aqui. Apesar do framework te oferecer a possibilidade de tratar o arquivo de configuração de acesso ao BD como um script, e você poder até mesmo subverter o padrão e possuir apenas um ambiente, minha sugestão para você é que evite ao máximo possível estes recursos.

    Não porque eles podem danificar seu banco de dados ou tornar sua aplicação um monstro, mas sim porque dificulta o entendimento de novos membros que venham a entrar em sua equipe. Afinal de contas, 99,9% dos programadores esperam o comportamento padrão do Grails, não um “arquivo de configuração vivo”, não é mesmo? Porém, se mesmo assim optar por usar estes recursos, faça o possível para documentar estas peculiaridades do seu sistema ok?

    Grails: testando sua aplicação

    Sabe esta aplicação linda que você está escrevendo em Grails usando todo o dinamismo que o framework te oferece?  Funciona perfeitamente, e em sua cabeça não aparece uma situação sequer na qual algo possa dar errado, certo?

    Como você pode ter certeza de que esta aplicação está funcionando? Só há uma maneira: testando, e da maneira certa, ou seja, com testes automatizados. Não há como evitar, sua aplicação VAI virar um monstrinho abominável se voce não escrever testes automatizados.

    Os testes automatizados são a sua rede de segurança (safety net): são eles que te dão segurança no momento da manutenção.

    Neste post meu objetivo é expor como tirar proveito do Testing Framework, que é o framework de testes adotado pelo Grails. Porém, antes de começar quero acabar com um mito cretino.

    “Eu não tenho tempo para escrever testes!”

    Papo furado! Se o programador não escreve testes, como pode saber que sua aplicação está DE FATO funcionando? Debugando e executando a aplicação manualmente. E sabe qual o grande problema com esta prática? Ela consome tempo: muito mais do que a escrita e execução dos testes automatizados. E sabe o que é pior? Ainda é sucetível a erros.

    Isto sem mencionar que os testes unitários e de integração acabam se tornando a melhor documentação possível para o seu código, pois descrevem exatamente como espera-se que este funcione.

    Lido este argumento sua desculpa para ser irresponsável evaporou.

    Testes unitários e de integração: qual a diferença?

    Testes unitários levam em consideração o objeto a ser verificado isolado. Não há conexões com bancos de dados, web services ou qualquer outro tipo de componente: a classe deve ser vista como um elemento autista. Como veremos, isto trás algumas dificuldades que o testing framework do Grails nos ajuda a resolver de uma maneira simples usando mock objects.

    Testes de integração, por sua vez, levam em consideração, como o próprio nome já diz, a integração do objeto a ser testado com componentes externos, como por exemplo bancos de dados, web services ou outros serviços de natureza diversa. Testes de integração são portanto muito mais caros do ponto de vista computacional, visto que precisamos iniciar a aplicação para que estes possam ser executados.

    É muito comum encontrar testes unitários que, na realidade, são de integração. Os mock objects entram em cena portanto como elementos externos “de mentirinha”, que nos permitem tratar o objeto isoladamente. Veremos mais sobre este recurso neste post.

    Criando seus testes

    Todos os testes unitários se encontram no diretório test/unit (ou integration) presente na raiz do seu projeto Grails. Já reparou que toda vez que você cria uma classe de domínio, controlador ou biblioteca de tags (e outros artefatos), automaticamente são incluidos no diretório test/unit?

    Há três maneiras de se criar estes testes:

    1. O Grails os cria automaticamente pra você
    2. Criando a classe de teste manualmente (nesta seção ficará claro como isto é feito)
    3. Usando o comando “grails create-unit-test”

    Assim como diversos aspectos do Grails, aqui também devemos nos ater a algumas convenções. Toda classe de teste possui o sufixo “Tests” em seu nome. Sendo assim, os testes unitários para a classe de domínio Usuario, por exemplo, ficariam em test/unit/UsuarioTests.groovy.

    Uma classe de teste vazia é simples como a abaixo:

    
    import grails.test.*
    
    class UsuarioTests extends GrailsUnitTestCase {
    protected void setUp() {}
    
    protected void tearDown() {}
    
    void testSomething() {}
    }
    
    

    O comando “grails create-unit-test” ou “grails create-integration-test” deve receber o nome do teste unitário ou de integração a ser gerado. Você não precisa incluir o “Tests” no final do arquivo, Grails o incluirá para você.

    Testando classes de domínio

    Quando lidamos com linguagens dinâmicas como Groovy precisamos lidar com o seguinte problema: como testar uma classe que contém métodos e atributos que só serão injetados em tempo de execução? Funções como save(), validate() ou constraints só funcionam após injetados pelo framework.

    Podemos escrever testes de integração. O problema é que leva tempo até a aplicação ser iniciada, o que irá reduzir a sua produtividade. O ideal é podermos executar testes unitários, que por sua própria natureza são ordens de magnitude mais rápidos. A solução para o problema é mockar seus objetos usando o Testing Framework do Grails!

    (assim como o GORM é baseado no Hibernate, o Testing Framework é baseado no JUnit que você já conhece (ou deveria conhecer! :D))

    Para ilustrar, tenha como base esta classe de domínio:

    
    class Usuario {
    String nome
    String login
    
    static constraints = {
    nome(nullable:false, blank:false, maxSize:128, unique:true)
    login(nullable:false, blank:false, maxSize:16, unique:true)
    }
    }
    
    

    Nosso teste unitário encontra-se na classe abaixo:

    
    import grails.test.*
    
    class UsuarioTests  extends GrailsUnitTestCase {
    protected void setUp() {super.setUp()}
    
    protected void tearDown() {super.tearDown()}
    
    void testConstraints() {
    mockDomain Usuario
    def usuario = new Usuario()
    assertFalse usuario.validate()
    def usuario_ok = new Usuario(nome:"Joselino", login: "joca")
    assertTrue usuario_ok.validate()
    }
    
    void testUnicidade() {
    mockDomain Usuario, []
    def usuario1 = new Usuario(nome: "Joselino", login: "jose")
    usuario1.save()
    def usuario2 = new Usuario(nome:"Joselino", login:"joca")
    assertFalse usuario2.validate() // já existe um Joselino!
    
    }
    
    }
    
    

    Repare que interessante: mesmo se tratando de um teste unitário estou testando métodos que só existem em tempo de execução: no caso, o validate. Para isto, uso o método mockDomain, herdado de GrailsUnitTestCase. Este injeta na classe domínio todos os métodos que uma classe de respeito deste tipo deve ter, como por exemplo os métodos de validação, save(), delete(), etc.

    Assim é possível testar fácilmente a validação. Mais interessante ainda é o segundo teste: testUnicidade. Repare que passo para o método mockDomain uma lista vazia. Quando evoco o método save(), este objeto é na realidade armazenado naquela lista que passei como parâmetro, simulando assim um banco de dados! Não é legal? Assim posso verificar se a constraint unique está de fato funcionando ou não.

    No caso de testes de integração, óbviamente você não precisa do método mockDomain, pois as classes já estão prontas.

    Testes unitários para controladores

    É muito comum encontrarmos projetos nos quais apenas classes de domínio são testadas. Após ler esta seção, sua desculpa para não testar seus controladores acabou! :D

    Para testar suas classes, você deve criar um teste tal como faria normalmente. A diferença é que este teste não extenderá a classe GrailsUnitTestCase, mas sim ControllerUnitTestCase. Nosso controlador de exemplo segue abaixo. Observe que ele só tem uma action.

    
    class BoboController {
    
    def bobo = {
    
    if (! params.valor) {
    redirect(action:"outra", controller:"outro")
                    return
    }
    switch (params.valor) {
    case "boo":
    render "Não sou bobo não"
    break
    case "bonito"
    return [resposta:"sou lindo mesmo!"]
    case "nada"
    throw new Exception("Nada???")
    }
    }
    
    }
    
    

    Escrevi alguns testes para esta classe que ilustra bem o que podemos fazer com este framework:

    import grails.test.*
    
    class BoboControllerTests extends ControllerUnitTestCase {
        protected void setUp() {
            super.setUp()
        }
    
        protected void tearDown() {
            super.tearDown()
        }
    
        void testRedirect() {
    		controller.bobo()
    		assertEquals "outra", redirectArgs.action
    		assertEquals "outro", redirectArgs.controller
        }
    
    	void testRender() {
    		mockParams.valor = "bobo"
    		controller.bobo()
    		assertEquals mockResponse.contentAsString, "Não sou bobo não"
    	}
    
    	void testModel() {
    		mockParams.valor = "bonito"
    		def model = controller.bobo()
    		assertEquals model.resposta, "sou lindo mesmo!"
    	}
    
    }
    

    Nosso primeiro teste é o de redirecionamento. Observe o método testRedirect(). A classe ControllerUnitTestCase possui um atributo chamado chamado controller, que simula o nosso controlador (o controlador é identificado por default pelo nome que demos à classe do nosso teste).  Chamando nossa action sem nenhum parametro, esperamos, pelo código que expus acima, que sejamos redirecionados para a action “outra” do controller “outro”.

    Entra em cena então outro atributo de nossa classe: redirectArgs. Ele normalmente possui 3 parâmetros: controller, action e model. Assim podemos ver se o nosso controlador está se comportando como esperavamos inicialmente.

    Se quisermos testar o funcionamento de nosso controlador passando-lhe parâmetros, usamos o atributo mockParams, que funciona exatamente como o params que estamos acostumados a trabalhar. Primeiro devemos incluir os valores neste atributo e em seguida executar nossa action para ver o resultado. Em testeRender podemos ver um exemplo de como verificar se o texto renderizado pelo nosso controlador foi o que esperávamos receber. Para isto, usamos o atributo mockResponse.

    Finalmente, inclui também um teste para o valor de retorno de nosso controlador. Observe o método testModel. Basta executar nossa action como se fosse uma função convencional. O restante do código é similar ao que escreveriamos usando um teste unitário convencional.

    Há mais alguns atributos que merecem ser mencionados: são estes:

    • mockRequest: usado para simular uma instância de HttpServletRequest
    • mockSession: usado para simular uma sessão (você pode, por exemplo, verificar se seu controller alterou ou não sua sessão após a execução de uma action, o que é MUITO útil)
    • mockFlash: usado para simular o contexto flash. Muito útil para verificar mensagens de alerta que precisam ser enviadas ao usuário, por exemplo.

    Executando os testes

    Com sua aplicação funcionando, o próximo passo é executar seus testes. Para isto, você usa o comando “grails test-app”, que irá primeiro executar todos os seus testes.

    Caso queira executar apenas alguns testes, basta passar como parâmetro os nomes dos testes excluindo o sufixo “Tests”, como por exemplo

    grails test-app BoboController

    Para executar apenas testes unitários, execute

    grails test-app unit

    e para executar apenas os testes de integração, execute

    grails test-app integration

    Executados os seus testes, será criado o diretório target/test-reports em seu projeto, contendo o relatório de execução dos seus testes. Caso esteja usando Grails 1.1, estes relatórios irão estar em test/test-reports.

    Concluindo

    Um programador que não escreve testes automatizados é como um cirurgião que não lava as mãos antes de uma cirurgia (não me lembro aonde li isto). Com Grails, a escrita dos testes, como pode ser visto, é um processo simples e direto, que irá lhe garantir noites de sono tranquilas após ter entregue seus sistemas.

    Agora, se mesmo assim você ainda não quer escrever seus testes, bem: sinto muito, você deve procurar outro ramo se quiser manter um nível mínimo de saúde. :D

    Grails: entendendo as validações (constraints)

    No meu último post falei sobre alguns detalhes poucos conhecidos das buscas por critérios. Agora chegou a hora de expor algumas coisas bem legais sobre as validações, aka constraints, oferecidas pelo framework.

    O básico

    As constraints nos permitem definir declarativamente as regras de validação que devemos aplicar às nossas classes de domínio. São muito similares ao projeto “Hibernate Validator”. A diferença é que ao invés de usarmos anotações, iremos usar uma DSL interna definida pelo framework. Assim como no caso da busca por critérios, a DSL usada é baseada no recurso builder presente na linguagem Groovy.

    Para declararmos as regras de validação, devemos incluir um bloco estático na nossa classe de domínio chamado constraints, tal como no exemplo abaixo:

    
    class DominioBonito {
    String nome
    Integer codigo
    String email
    
    static constraints = {
    nome (nullable:false, blank:false, unique:true)
    codigo(min:1)
    email(email:true)
    }
    }
    
    

    A sintaxe é muito simples: em cada linha você deverá incluir o nome do campo a ser validado, seguido de um par de parênteses contendo as regras a ser aplicadas. Cada regra recebe um ou mais parâmetros, que variam de acordo com a sua implementação. Não se assuste com isto, pois estes atributos se tornarão familiares a você com o tempo.

    Todas as constraints default do Grails podem ser acessadas neste link: http://grails.org/doc/latest/ref/Constraints/Usage.html (salve-o em seus bookmarks para referência, pois é uma mão na roda)

    Agora que o básico já foi dito, podemos ver detalhes menos conhecidos deste recurso.

    Constraints e scaffolding

    Eis um detalhe das constraints que não acho bacana: a sua presença influencia o scaffolding. Caso você queira definir a ordem em que os atributos de suas classes de domínio são expostos por este recurso, tudo o que você deve fazer é alterar a ordem na qual os atributos são definidos no bloco constraints da sua classe de domínio.

    Há inclusive algumas constraints cujo objetivo é justamente definir regras para o scaffolding. São elas:

    display (true ou false): define se o campo vai aparecer ou não nas páginas geradas pelo scaffolding
    editable (true ou false): define se o campo será editável no scaffolding ou não
    format (string): no caso de datas e números, define qual o formato no qual estes serão expostos, digitados pelo usuário (útil d+!)
    password (true ou false): se você definir como true, será exposto um input do tipo password na sua interface gráfica
    widget (string): define qual widget deverá ser renderizado. Você deve apenas fornecer qual o nome da tag usada, como por exemplo textarea

    Dica: evite este recurso. A classe de domínio deve ser a parte de negócio da sua aplicação, não a responsável pela visualização.

    Constraints e GORM

    As constraints também influenciam o funcionamento do GORM. No caso da criação das tabelas do banco de dados estar sendo executada pelo framework, as constraints são usadas para definir o tamanho dos campos, assim como o fato de aceitarem ou não valores nulos. Como exemplos, posso citar as seguintes constraints:

    maxSize: no caso de campos do tipo varchar ou char, define qual o seu tamanho
    nullable: define se o campo pode aceitar valores nulos ou não
    unique: cria um índice de unicidade para a coluna relacionada

    No caso de maxSize, caso não seja incluida, será usado como valor default de tamanho para campos textuais o padrão do SGBD que, normalmente, é 255 caracteres.

    Constraints customizadas

    Ok, Grails te oferece uma série de constraints úteis, mas e se você quiser criar uma personalizada? Por exemplo: no cadastro de usuários, ter uma classe de domínio na qual seja verificada a igualdade das senhas digitadas. Como você faz isto? Neste caso, você usa a constraint validator. Veja o exemplo abaixo:

    
    class Usuario {
    
    String nome
    String login
    String senha1
    String senha2
    
    static constraints = {
    senha2(validator:  {valor, objeto ->
    objeto.properties['senha2'] == valor
    })
    }
    
    }
    
    

    A constraint valiator neste caso recebe como valor uma closure que deverá possuir dois parâmetros, obrigatóriamente nesta ordem: valor, objeto. O primeiro representa o valor a ser validado, e o segundo o objeto a ser verificado que, no caso, é a sua instância da classse de domínio a ser validada. O objeto precisa ser passado como parâmetro porque as constraints são um bloco estático. Caso contrário, não haveria como usar este recurso em um ambiente concorrente como aplicações web.

    Se o valor da constraint é true, é sinal de que o teste passou. No entanto, esta constraint também pode retornar uma string. No caso, esta string representa uma mensagem de erro, que é definida nos arquivos de mensagens do Grails, presentes no diretório grails-app/i18n. Eu poderia reescrever o exemplo acima da seguinte maneira portanto:

    
    class Usuario {
    
    String nome
    String login
    String senha1
    String senha2
    
    static constraints = {
     senha2(validator:  {valor, objeto ->
    if (objeto.properties['senha2'] == valor)
    return true
    else
    return "erro.senhas.diferentes"
    })
    }
    
    }
    
    

    E esta mensagem seria exposta na minha camada de visualização tirando proveito do recurso de internacionalização do Grails.

    Você também pode usar esta constraint passando como parâmetro uma closure que possua um único parâmetro, tal como neste exemplo:

    
    class Testolina {
    Integer valor
    static constraints = {
    valor(validator: {it % 2 == 0}
    }
    }
    
    

    Neste caso, apenas o valor é verificado, que deverá ser um número par.

    Constraints globais e compartilhadas

    Um recurso muito útil e pouco comentado do Grails é a possibilidade de se criar regras de validação globais e compartilhadas. Imagine a seguinte situação: no seu projeto, por default, todos os atributos devem ser não nulos por default. Não é chato ter de repetir esta regra em todas as suas classes de domínio?

    Você inclui uma regra de validação global no arquivo grails-app/conf/Config.groovy. Basta adicionar um código similar ao abaixo:

    
    grails.gorm.default.constraints = {
    '*'(nullable:false)
    }
    
    

    O * diz que esta regra se aplica a todos os atributos. Hei! Se eu inclui *, eu também posso incluir o nome de um atributo padrão em minhas classes, como, por exemplo, “nome”? Claro! Veja o exemplo abaixo:

    
    grails.gorm.default.constraints = {
    'nome'(nullable:false, maxSize:128)
    }
    
    

    Não é legal? Bom: esta é uma constraint global, mas o que seria uma constraint compartilhada?

    Uma constraint compartilhada é uma regra de validação que pode ser aplicada em mais de um local nas suas classes de domínio. Vamos supor que você tenha vários atributos os quais devam, obrigatóriamente, possuir no máximo 20 caracteres. Você incluiria no mesmo arquivo um código similar ao abaixo:

    
    grails.gorm.default.constraints = {
    compartilhada(maxSize:20)
    }
    
    

    E para usá-la em suas classes de domínio, a declararia tal como abaixo:

    
    class Testolina {
    String rua
    static constraints = {
    rua (shared: "compartilhada")
    }
    }
    
    

    Fácil e direto ao ponto. Eu amo isto!

    Como validar constraints

    Ok, você sabe como declarar suas regras de validação. Agora precisa saber como usá-las. No caso do Grails, toda classe de domínio possui injetado um método chamado validate. Caso alguma regra de validação falhe, a variável interna errors da classe de domínio será alterada incluindo os atributos que estão com problema. O código abaixo ilustra bem a situação:

    
    dominio.validate()
    if (dominio.hasErrors()) {
    //danou-se! Há erros aqui!
    }
    
    

    O que pouca gente sabe é que você pode validar apenas alguns campos ao invés de todos se quiser. Como fazer isto? Simples: passe para o método validate() uma lista contendo os nomes dos campos a serem validados, tal como no código abaixo:

    
    dominio.validate(['nome', 'email'])
    if (dominio.hasErrors()) {
    //danou-se! ou o atributo nome ou o atributo email estão ferrados! Droga!
    }
    
    

    E este atributo errors hein?

    Como mencionei, toda classe de domínio possui injetado um atributo chamado errors. Este na realidade é uma instância da interface Errors do Spring. E sabe o que é mais legal nesta interface? Ela tem um método chamado reject implementado de varias formas.

    Se for necessário incluir uma validação que vá além das constraints, vamos supor, alguma regra de negócio maluca, você poderia incluir uma validação ALÉM das constraints. Vamos supor que por alguma razão sinistra da vida, você precise adicionar uma validação que não seja feita por constraints (por exemplo, algo a ser validado ANTES do método save ser executado). Você poderia escrever um código como o abaixo:

    
    class DominioMaluco {
    def  beforeQualquerCoisa= {
    if (condicaoMaluca) {
    errors.reject("codigo.do.erro")
    }
    }
    }
    
    

    No caso, o método reject está adicionando ao atributo errors um novo código de erro. Aquele mesmo tipo de código de erro que incluimos nas mensagens de internacionalização padrão do Grails.

    Sugiro que você dê uma lida nesta interface. Ela vai te possibilitar ir BEM além da validação padrão oferecida pelo framework.

    Concluindo

    Neste post vimos algo além do feijão com arroz que normalmente encontramos sobre o assunto. Como ficou claro, as constraints possuem uma profundidade muito maior que a esperada.

    Minha sugestão para quem estiver começando no assunto é a seguinte: tenha nos seus bookmarks o link que expus acima contendo as constraints default do Grails. Estando habituado com estas, estude seu código fonte (é surpreendentemente simples).

    Tendo feito isto, parta para as constraints customizadas e, em seguida, caso alguma coisa muito sinistra aconteça, ai sim use e abuse da API de validação do Spring, que é a base em cima da qual as constraints são construídas.