Java annotations. Que bruxaria é essa?

Sharing is caring!

 

Muitas vezes nós usamos ferramentas ou trabalhamos com features das nossas linguagens de programação sem saber como elas funcionam ou até sem saber porque elas estão ali, e uma coisa é nítida no universo Java, quando você começa a trabalhar em projetos maiores que exigem mais controle, ou principalmente quando usamos frameworks como Spring,  fazemos uso constantemente de um recurso que a maioria os iniciantes não entendem o real significado. Estou falando das Annotations.

“Annotations não é aquele negocim que a gente põe nas classes pra falar que é um controller e coisa e tal?”

Exatamente, as annotations foram inseridas no Java 5 com o objetivo de simplificar a adição de metadados às classes e permitir aos desenvolvedores reduzir o uso de arquivos xml que são uma praga que são chatos de criar e configurar.

Definição de metadado, by Google:

Os metadados descritos por Dublin Core podem ser definidos como conjunto de elementos de metadados planejados para facilitar a descrição de recursos eletrônicos. Eles são desenvolvidos a partir e em função de dados, por isto que é designado como “dados sobre dados” ou “informação sobre a informação”.

É exatamente o que fazemos, usamos essas meta informações pra dizer à um framework ou uma biblioteca qual a utilidade, função ou categoria daquela classe, atributo ou método. Se você nunca trabalhou com JavaEE ou com algum framework como citei, muito provavelmente já se deparou com annotations em outros cenários, como @Override, @Deprecated, @Test e etc.

Até esse ponto acho que ninguém ainda está surpreso, vamos agora entrar nos detalhes de funcionamento dessa feature.

Criando minha própria annotation

Vamos imaginar um cenário onde precisamos imprimir na tela as propriedades de uma classe User, mas essa classe tem alguns atributos que gostaríamos de omitir, como sua senha por exemplo, vamos fazer isso usando annotations para entender o funcionamento.

Vamos começar com a nossa classe User:

Certo, agora gostaríamos de especificar via uma annotation por nós criada, quais atributos queremos imprimir a partir do usuário registrado.

O que queremos na verdade é algo assim:

Perfeito! Agora vamos avaliar a sintaxe da declaração de annotations em Java:

Muito simples não?

Podemos agora fazer uso de algumas configurações para especificar seu funcionamento:

A annotation @Target serve para especificar onde poderemos utilizar a nossa annotation, se ela pode ser adicionada a um método, uma classe, etc.

Já a annotation @Retention indica em quais momentos a máquina virtual terá que lidar com essa annotation, por exemplo, a annotation @Override só serve em tempo de compilação, já a annotation @Test é necessária em tempo de execução.

Como avaliaremos a existência da annotation durante a execução, deixaremos a RetentionPolicy.RUNTIME.

Ainda precisamos adicionar o atributo label da nossa annotation:

Agora vamos a nossa classe de impressão:

Aqui nós utilizamos a api de reflecion do Java para extrair as meta informações que precisamos dos métodos da classe User.

Todo objeto em java possui o método chamado ‘getClass()’ que retorna um tipo especial de objeto que representa a classe do qual o objeto foi instanciado, a partir daí chamamos o método ‘getDeclaredMethods()’ que nos retorna um array com os métodos declarados naquela classe.

A partir do objeto ‘method’ podemos extrair as meta informações das annotations através do ‘getAnnotation()’ e usamos isso para imprimir apenas os valores que nos interessam.

Analisando os benefícios

Como tudo na vida de programador, cada técnica tem suas vantagens e seu preço, por isso vamos agora analisar nossa solução e levantar alguns pontos importantes:

  • Apesar da melhor legibilidade da classe User, bem como a simplicidade de adicionar ou remover annotatios, a classe Printer faz uso de reflection, o que deixa as coisas um pouco mais confusas por lá. Por tanto aumentos a legibilidade da classe User ao custo de complicar um pouco a legibilidade da classe Printer.
  • Do ponto de vista da performance, é obvio que fazer um ‘getName()’ seguindo de um ‘getEmail()’ direto é mais performático do que fazer esses loops e extrair essas metainformações da classe. Então mesmo que eu não consiga dizer o quanto de performance perdemos, é óbvio dizer que perdemos um pouco.
  • Agora sobre a manutenibilidade, também é óbvio que simplificamos o processo de adição e remoção de elementos que serão impressos, por tanto será muito fácil de mudar essas regras caso nosso sistema seja alvo de mudanças contínuas.

Conclusão

Para esse nosso exemplo tivemos um grande benefício quanto a legibilidade da área de domínio, e a flexibilidade a mudanças a um custo pequeno de performance.

Para problemas simples como esse nosso exemplo, uma impressão direta poderia ser muito mais rápida de se desenvolver, mas fica aí uma bela dica que você pode aproveitar em outros casos onde sua aplicação precisa ser mais flexível a mudanças.

Espero que façam bom proveito dessas dicas.

Abraços! Até a próxima 🙂

Sharing is caring!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *