Um exemplo comum é o JUnit que permite uso de anotações para realizar testes de caso. De qualquer forma, aqui vai um exemplo prático:
Classe utilitária usada para vasculhar os classpath por classes que contenham a anotação:
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassFinder {
private static List<Class<?>> classes;
private static List<Class<?>> scan() {
// initializes the List
classes = new ArrayList<Class<?>>();
// and gets all URLs
URLClassLoader urlLoader = (URLClassLoader) ClassLoader
.getSystemClassLoader();
URL[] urls = urlLoader.getURLs();
// iterate
for (URL url : urls) {
File location = null;
try {
location = new File(url.toURI());
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
// and for each directory, find the classes
if (location.isDirectory()) {
getClassesInDirectory(null, location);
} else {
getClassesInJar(location);
}
}
return classes;
}
private static void getClassesInDirectory(String parent, File location) {
File[] files = location.listFiles();
StringBuilder builder = null;
for (File file : files) {
builder = new StringBuilder(100);
builder.append(parent).append("/").append(file.getName());
String name = (parent == null ? file.getName() : builder.toString());
if (file.isDirectory()) {
getClassesInDirectory(name, file);
} else if (file.getName().endsWith(".class")) {
addClass(name);
}
}
}
private static void getClassesInJar(File location) {
try {
JarFile jar = new JarFile(location);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (!entry.isDirectory() && name.endsWith(".class")) {
addClass(name);
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
private static void addClass(String name) {
String className = name.replaceAll("\\" + File.separator, ".")
.substring(0, name.lastIndexOf(".class"));
try {
classes.add(Class.forName(className));
} catch (ClassNotFoundException e) {
// do nothing (must not occur)
}
}
public static List<Class<?>> getAnnotatedClasses(
Class<? extends Annotation> filter) {
List<Class<?>> filtered = new ArrayList<Class<?>>();
for (Class<?> c : scan()) {
if (c.isAnnotationPresent(filter)) {
filtered.add(c);
}
}
return filtered;
}
}
A anotação propriamente dita:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Criamos uma anotação que recebe o nome do método que executaremos.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Plugin {
String method();
}
Duas classes que contenham essa anotação:
/**
* Essa classe servirá de exemplo e executará o método {@link #abc()}
*/
@Plugin(method = "abc")
public class MeuPlugin1 {
// classe de exemplo #1
public MeuPlugin1() {
System.out.println("Construtor de MeuPlugin1");
}
public void abc() {
System.out.println("O método executado foi abc()");
}
}
/**
* Essa classe servirá de exemplo e executará o método {@link #test()}
*/
@Plugin(method = "test")
public class MeuPlugin2 {
// classe de exemplo #2
public MeuPlugin2() {
System.out.println("Construtor de MeuPlugin2");
}
public void test() {
System.out.println("O método executado foi test()");
}
}
E a classe principal:
public class ListarPlugins {
public static void main(String[] args) throws Exception {
// para cada classe que contenha essa anotação
for (Class<?> c : ClassFinder.getAnnotatedClasses(Plugin.class)) {
// criamos uma instância dessa classe
Object instance = c.newInstance();
// pegamos o nome do método a partir da anotação
String method = c.getAnnotation(Plugin.class).method();
// e invocamos o método
c.getMethod(method).invoke(instance);
}
}
}