sexta-feira, maio 11, 2007

Annotations - Primeiro contato

Dae, tudo tranquilo?
Bom esses dias (depois de ter dado uma estudada em threads) andei dando uma aprofundada em Annotations.

Pó que saco, tudo que era lugar que eu lia sobre dizia a mesma coisa: anotações são meta-dados que blablabla... E uns exemplos muito complexos pra quem tava querendo entender para que um dia EU usaria essa funcionalidade do Java.v

Bem, então... hã... hun... pensei, pra mim ver para que serve tenho que fazer um exemplo, seja ele bizarro ou real eu preciso fazer. Então defini o seguinte:

Um POJO chamado Cliente (que original!);
Uma annotation chamada Validar;
Uma classe que interaja com meu POJO chamada CadastroCliente;
Uma classe que use dos campos anotados do meu POJO fazendo alguma coisa, neste caso validando-o.

Então o seguinte, annotations nada mais são do que meta-dados que estão nas classes e não servem pra pombas nenhuma, a não ser que alguém saiba o que fazer com eles. Exemplos clássicos são o modificador transient, que é uma anotação que informa ao mecanismo de serialização que o campo não deve ser serializado, a tag @deprecated do Java Doc, que indica que um método ira ser descontinuado em versões futuras da classe, e por aí vai. A vantagem que agora o desenvolvedor pode criar as suas anotações.

Bem o que meu exemplo faz é o seguinte, todo campo no meu POJO que tiver marcado com a anotação @Validar vai ser validado por um mecanismo através de reflection (papo para ouuuuutro post :P ).

Então criei a anotação, que nada mais é do que uma “interface” com @ antes da palavra reservada interface e que eu posso definir um nível de atuação para ela, no meu casso campos (poderia ser método, classe, etc... veja na API java.lang.annotation.ElementType os tipos permitidos) e que será usada em tempo de execução (também há uma lista de valor fixos na API java.lang.annotation.RetentionPolicy):

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Validar {
}

Depois disso criei meu POJO, e disse quais os campos dele serão validados:

public class Cliente {

    @Validar
    private String nomeCompleto;

    @Validar
    private int idade;
    
    private String email;

    public String getNomeCompleto() {
        return nomeCompleto;
    }

    public void setNomeCompleto(String nomeCompleto) {
        this.nomeCompleto = nomeCompleto;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Cliente() {
    }

    public Cliente(String nome, int idade) {
        this.nomeCompleto = nome;
        this.idade = idade;
    }

    public Cliente(String nome, int idade, String email){
        this.nomeCompleto = nome;
        this.idade = idade;
        this.email = email;
    }
}

Note que o campo que armazenará o e-mail do cliente não será validado, poderá ser nulo ou qualquer texto inválido para endereço eletrônico.

Agora sim, meu validador que vai pegar o objeto ver seus campos, ver os que estão “anotados” e fazer algumas validações:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ValidadorCadastro {
    public static String nvl(String entrada) {
        String saida = "";

        if(entrada == null) {
            saida = "";
        }
        else {
            saida = entrada;
        }

        return saida;
    }

    public List<String> validarCadastro(Cliente c) throws IllegalAccessError, Exception {

        Field[] fields = c.getClass().getDeclaredFields();

        String nomeCliente = null;

        Integer idade = null;

        List<String> erros = new ArrayList<String>();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Validar.class)) {

                field.setAccessible(true);

                if(field.getName().equals
("nomeCompleto")) {

                    nomeCliente = (String)field.get(c);
                    if(nvl(nomeCliente).length() < 4) {
                        erros.add("O nome do cliente deve ter mais " +
                                  "de 4 caracteres.");
                    }
                }

                if(field.getName().equals("idade")) {
                    idade = (Integer)field.get(c);
                    if(idade < 18) {
                        erros.add("O cliente deve ser maior de idade.");
                    }
                }

                if (field.get(c) == null) {
                    erros.add("Campo [" + field.getName() + "] não " +
                              "preenchido.");
                }
            }
        }

        return erros;
    }
}

E uma classe simples que interaja com o POJO e o validador:

import java.util.List;

public class CadastroCliente {

    public static void main(String[] args) {
        Cliente c0 = new Cliente("Jean Jorge Michel", 25);

        List<String> errosCadastro = null;

        ValidadorCadastro vc = new ValidadorCadastro();

        try {
            errosCadastro = vc.validarCadastro(c0);

            if(! errosCadastro.isEmpty()) {
                for(String erroOcorrido : errosCadastro) {
                    System.out.println(erroOcorrido);
                }
            }
            else {
                System.out.println("Cadastro concluído com sucesso!");
            }
        }
        catch(IllegalAccessError e) {
            e.printStackTrace();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}

Rodando a classe assim como está não há problemas, vai passar na validação... agora troque o nome, diminua a idade, não informe o nome... e a lista de problemas encontrados será exibida.

Bom, é uma aplicação para as anotações mas claro que há outras, como configuração de frameworks por exemplo. Veja o Hibernate annotation :).

Era isso, de tema para casa fica validar o campo e-mail também :D.

Gostou, não gostou, achou um erro, quer me xingar: comente o post!

6 comentários:

Gabriel disse...

Cara, muito bom o exemplo, simples e objetivo.
Valeu

Jean Michel disse...

Vlw Gabriel, muito obrigado pelo comentário é sem dúvida um insentivo ao blog.

Um abraço e continue frequentando o blog e comentando :D

Diego disse...

kra, muito fera esse teu artigo, gostei pra caralho,
me ajudou muuuuito.
obrigado mesmo.
e garanto q ajudará muitas outras pessoas também.
Abraços.

João disse...

muito bom, a sério! deu pa entender tudinho!
simples e claro

saisso disse...

Eu tinha visto um exemplo sobre anotações validando e tal, mas acabei perdendo, hoje estou precisando novamente e fui "buscar" na internet, mas, como vc mesmo citou, em muitos lugares dizem que anotações são meta-dados... hehehe

Vlw ae

leleu_devil disse...

Valeu , muito obrigado, esse post salvou minha vida pra concluir meu projeto de final de curso!!!!

já tava perdendo a esperança...
"luz no fim do tunel"