Numa discussão com um amigo, surgiu o tema sobre como classificar uma annotation. Será um interface ou uma classe, visto que embora seja definido com @ interface, podemos atribuir e retirar valores da annotation, indiciando que existe uma implementação dos métodos.
Na realidade, uma annotation é um tipo de interface. Tal como todas as classes que criamos extendem implícitamente a classe Object, sempre que criamos uma annotation esta extende implícitamente o interface Annotation. O interface annotation tem a seguinte definição:
public interface Annotation {
boolean equals(Object obj);
int hashpre();
String toString();
Class extends Annotation> annotationType();
}
Se quisermos criar uma nova annotation, podemos declará-la da seguinte forma:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @ interface Teste{
String umMembro();
}
Definimos uma annotation de teste com um membro do tipo String. Definimos com a Retention que a annotation vai estar disponível em runtime, e definimos no target que esta annotation pode ser utilizada em métodos. Utilizaríamos a annotation, por exemplo, neste simples bloco de código:
public class AnnotationsTest {
@Teste(umMembro="textoMembro")
public void umMetodo() {}
}
Estamos então a anotar o nosso método com a anotação que criámos anteriormente, e a definir uma propriedade exemplo. A primeira questão a reparar é que a annotation é um interface mas estamos a atribuir-lhe valores quando utilizamos a annotation, e podemos consultar as annotations definidas em run-time (porque colocámos retention = RUNTIME na definição da annotation). Podemos simplesmente, adicionar um método main a esta nossa classe AnnotationsTest para tentar perceber um pouco melhor o que acontece.
public static void main(String[] args) throws NoSuchMethodException {<
AnnotationsTest at = new AnnotationsTest();
Annotation[] annots = at.getClass().getMethod("umMetodo").getAnnotations();
for(Annotation annot : annots) {
System.out.println("Annotation? " + annot.annotationType().isAnnotation());
System.out.println("Interface? " + annot.annotationType().isInterface());
System.out.println("Nome da classe da annotation: " + annot.getClass());
System.out.println("Nome do tipo da annotation: " + annot.annotationType().toString());
Teste t = (Teste) annot;
System.out.println("Valor do umMembro: " + t.umMembro());
}
}
Na linha 3, vamos buscar todas as annotations do método umMetodo(). Isto é possível, porque com a introdução das annotations no Java 5, todos os elementos sobre os quais podemos aplicar anotações passaram a implementar o interface AnnotatedElement, que fornece um modo de se aceder às annotations numa classe, método, variável, parametro ou mesmo package. Depois percorremos a anotações e fazemos uns testes para ver o que nos diz sobre o que é uma anotação. O output é o seguinte:
Annotation? true Interface? true Nome da classe da annotation: class $Proxy3 Nome do tipo da annotation: interface zonaj.testes.annotations.Teste Valor do umMembro: textoMembro
As primeiras duas linhas confirma-se o que já se sabia, a Annotation é um interface. Na terceira linha vem a explicação para as nossas dúvidas: a classe da anotação é um $Proxy3, nitidamente um proxy gerado pelo compilador em run-time. Este proxy é que implementa automáticamente os métodos para as propriedades definidadas na nossa anotação, bem como os métodos do interface Annotation.
Nas duas outras linhas de output, vemos que o annotationType é o Teste que criámos e vemos como obter o valor indicado na anotação do método.
Este método de geração de proxies não é muito explicado mas funciona aproximadamente como o Annotation Processing Tool (apt) que é uma aplicação que nos permite criar factories para gerar proxies e processar anotações.
De resto, uma anotação não é uma classe, é um interface. Só é criado um proxy automaticamente para poder ser utilizada.

1 resposta até ao momento ↓
Alex // Dez 19, 2007 at 2:09
Parabêns! Gostei das explicações.
Mais de um modo conclusivo quais as vantagens de utilizar annotations?
Deixe um comentário