Busca de Annotations

2 respostas
J

Seguinte pessoal

Eu estou desenvolvendo uma engine de regras no meu sistema (sem utilizar o Drools pora algumas limitações). Até ai tudo bem, estou fazendo ela para ser altamente escalável, sem impactar em mudanças na engine para adição de novas regras.

A solução que eu tô desenvolendo deveria pegar todas as classes anotadas por uma anotação que eu criei (que devem implementar uma interface padrão de regras) e executa-las para obter o subconjunto de regras validas. Dessa forma, se uma nova regra for criada, bastará anotá-la futuramente e a engine deve automaticamente buscá-la.

só que não sei como eu faço para buscar todas as classes anotadas do projeto. A solução que eu vi foi buscar manualmente em todos os jars e pastas do projeto, mas isso não funciona pra mim, pq futurametne alguem pode adicionar uma regra em um novo jar no classpath do projeto, e o sistema deve automaticamente conseguir buscá-lo, sem alterar a engine.

Alguém tem uma ideia se existe algum método do tipo “getAllClassesAnnotatedInClasspath(nomeDaAnotacao)”, onde eu não precisaria informar nada nem de jar, nem de pacotes, nem de diretorios?

2 Respostas

M

Compile esta classe normalmente (‘javac ClassFinder.java’) e execute (‘java ClassFinder’).

Depois pegue um diretório qualquer que contenha arquivos .class e execute de novo, adicionando ao classpath (algo como ‘java -cp .:/tmp/classes ClassFinder’).

Depois execute novamente com um JAR no classpath (por exemplo, ‘java -cp .:/tmp/meujar.jar ClassFinder’).

Só lembrando que se estiver usando Windows, o separador de diretórios no classpath é o ponto e vírgula ( ; ) e não o dois pontos.

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 packageOrClass = (parent == null ? file.getName() : builder
					.toString());

			if (file.isDirectory()) {
				getClassesInDirectory(packageOrClass, file);
			} else if (file.getName().endsWith(".class")) {
				addClass(packageOrClass);
			}
		}
	}

	private static void addClass(String packageOrClass) {
		String className = packageOrClass.replaceAll("\\" + File.separator,
				"\\.").substring(0, packageOrClass.indexOf(".class"));
		try {
			classes.add(Class.forName(className));
		} catch (ClassNotFoundException e) {
			// do nothing (must not occur)
		}
	}

	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();
		}
	}

	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;
	}
	
	public static List<Class<?>> getAllClasses() {
		return scan();
	}
	
	public static void main(String[] args) {
		for (Class<?> c : getAllClasses()) {
			System.out.println(c.getName());
		}
	}
	
}
M

E só complementando: como você precisa só das classes anotadas, basta fazer:

List<Class<?>> classesQueTeInteressam = ClassFinder.getAnnotatedClasses(SuaAnotacao.class);
Criado 10 de dezembro de 2010
Ultima resposta 13 de dez. de 2010
Respostas 2
Participantes 2