Geralmente, nós usamos anotações, e não nos atentamos no que está acontecendo por tráz dos bastidores....
//anotação valor de um elemento
@ClassInfo(autor="James", dataDeCriacao="30/04/2011")
public class Foo {
...
}
Para criar a anotação você criaria como abaixo, lembre-se que a palavra interface, quando se cria uma anotação se refere ao tipo anotação!
@interface ClassInfo {
String autor() default "Fulano";
String dataDeCriacao();
}
Bom vamos aos conceitos:
:idea: Anotação é um Tipo
:idea: Pode ser vista como uma espécie de interface,
declarada com auxílio do caractere @
:idea: Tipos dos elementos: primitivos, String, enum,
anotação,Class ou array de um desses tipos
:idea: Elementos podem ter valor default
Temos que considerar que se a antoação tiver apenas um elemento e ele for denominado value podemos omitir:
@interface ClassInfo { //codigo fonte da anotação
String value();
}
@ClassInfo("James")//uso da anotação em uma classe qualquer
public class Foo {
Bom antes de continuar veja que você para criar sua própria anotação, apenas salvaria o arquivo "ClassInfo.java", e sendo assim sua anotação @ClassInfo estaria
disponível para o uso como foi o exemplo acima do uso na classe Foo.
Nós temos também as restrições que dizem onde uma anotação pode ser usada sendo algumas delas:
Restrições disponíveis:
[color=red]
ElementType.TYPE
ElementType.FIELD
ElementType.METHOD
ElementType.PARAMETER
...
[/color]
@Target(ElementType.METHOD)
@interface MetodoTestavel {
}
@ClassInfo("James")
public class Foo {
public void m1(String arg1) {
...
}
public void m2() {
...
}
@MetodoTestavel
public void m3() {
...
}
}
Acima foi criado uma anotação chamada MetodoTestavel que está sendo aplicada no método m3(), desta forma você pode definir em quais "tipos" poderá ser usada
sua interface!
Para acabar a história nos temos a política de retenção que definem quando a anotação pode ser usada sendo elas:
[color=red]RetentionPolicy.SOURCE[/color]
? Anotações existem somente no arquivo-fonte. São
descartadas pelo compilador ao produzir uma
representação binária
[color=red]RetentionPolicy.CLASS[/color]
? Anotação são preservadas na representação binária,
mas não necessitam estar disponíveis durante a execução
[color=red]RetentionPolicy.RUNTIME[/color]
? Anotações são preservadas na representação binária da
classe e devem estar disponíveis durante a execução
através do mecanismo de reflexão.
Exemplo:
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@interface ClassInfo {
String value();
}
Desta forma podemos facilmente tirar proveito de nossas anotações com o uso da API de refexão veja abaixo o "pedaço" de código:
Class <Foo> cls = Foo.class;
Annotation[] anots = cls.getAnnotations();
for (Annotation a: anots) {
Class ca = a.annotationType();
System.out.println( ca.getName() ); //ClassInfo
}
Veja que acima estamos "consultando" a classe e retornando as anotações que a Classe Foo possue....
Desta forma da para usar por exemplo chamada a métodos por meio de reflexion usando os proprios valores da anotação...
Para finalizar um exemplo prático, temos uma anotação chamada Teste, e uma classe Foo, vamos usar reflexion para chamar os métodos usando
os proprios valores da anotação, temos na classe Main.java três soluções possíveis para o caso. Abaixo o procedimento para você testar:
Salve anotação como Teste.java
Salve a classe Foo.java
E por fim temos uma classe de Teste que invoca os métodos passando como parâmetro os proprios valores da anotação:
Deixe a visibildade das classes transparente entre Si.
Teste.java
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.METHOD)
public @interface Teste {
String argumento() default "algum valor";
}
Foo.java
public class Foo {
public void m1(String s) {
System.out.println("m1 invocado com argumento = " + s);
}
@Teste(argumento="Valor para o teste 2")
public void m2(String s) {
System.out.println("m2 invocado com argumento = " + s);
}
//@Teste(argumento="Valor para o teste 3")
public void m3(String s) {
System.out.println("m3 invocado com argumento = " + s);
}
}
Main.java
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
solucao1();
solucao2();
solucao3(Teste.class, Foo.class);
}
private static void solucao1() throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
Class<Foo> c = Foo.class;
Object o = c.newInstance();
// Obtém os métodos da classe
Method[] ms = c.getDeclaredMethods();
for (Method m : ms) {
Teste t = m.getAnnotation(Teste.class);
if (t != null) {
t.argumento();
m.invoke(o, t.argumento());
}
}
}
private static void solucao2() throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
Class<Foo> c = Foo.class;
Object o = c.newInstance();
// Obtém os métodos da classe
Method[] ms = c.getDeclaredMethods();
for (Method m : ms) {
Annotation[] ts = m.getAnnotations();
for (Annotation t : ts) {
if (t.annotationType().isAssignableFrom(Teste.class)) {
m.invoke(o, ((Teste) t).argumento());
}
}
}
}
private static <T extends Annotation, U> void solucao3(
Class<T> tipoDaAnotacao, Class<U> c) throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
// Dos métodos declarados na anotação, verifica se existe um chamado
// 'argumento'
// Se não existir, retorna, pois a anotação informada como parâmetro
// para esse método
// não serve, pois não tem um elemento String chamado argumento.
Method[] msa = tipoDaAnotacao.getDeclaredMethods();
Method elemento = null;
for (Method ma : msa) {
if (ma.getName().equals("argumento")
&& ma.getReturnType().equals(String.class)) {
elemento = ma;
break;
}
}
if (elemento == null) {
return;
}
U o = c.newInstance();
// Obtém os métodos da classe
Method[] ms = c.getDeclaredMethods();
for (Method m : ms) {
T t = m.getAnnotation(tipoDaAnotacao);
if (t != null) {
String valorArgumento = (String) elemento.invoke(t);
m.invoke(o, valorArgumento);
}
}
}
}
Espero ter ajudado!