Scan classes with specified annotation under specified package.
steps:
* define annotation
* use annotation on class
* get class set with specified annotations under specified packages,
2 approach:
* spring (preferred)
use util class from spring:
ClassPathScanningCandidateComponentProvider
* reflections lib
this lib provide class/methods to do this,
but it's not as good as spring,
*
* iterate the class set, read annotation, take actions as need,
*
maven:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.9-RC1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency>
Util class:
package eric.j2se.anno;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
import org.reflections.Reflections;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
/**
* Util to get classes according to annotation on class in a specified package.
*
* @author eric
* @date Aug 5, 2014 12:36:42 PM
*/
public class PkgAnnoUtil {
/**
*
* <p>
* Scan class with specified annotation under specific packages, using util from spring.
* </p>
* <p>
* Sub package & inner class will be included.
* </p>
*
* @param pkgArray
* an array of package path,
* @param annoClazzArray
* an array of annotation class,
* @return
*/
public static Set<BeanDefinition> getBeanSetWithAnno(String pkgArray[], Class<? extends Annotation>[] annoClazzArray) {
// prepare scanner, with each annotation,
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
for (Class<? extends Annotation> annoclazz : annoClazzArray) {
scanner.addIncludeFilter(new AnnotationTypeFilter(annoclazz));
}
Set<BeanDefinition> beanSet = null;
// search with each package, and combine search result,
for (String pkg : pkgArray) {
if (beanSet == null) {
beanSet = scanner.findCandidateComponents(pkg);
} else {
beanSet.addAll(scanner.findCandidateComponents(pkg));
}
}
return beanSet;
}
/**
* <p>
* Scan class with specified annotation under a specific package, using a lib called "reflections".
* </p>
* <p>
* Sub package & inner class will be included.
* </p>
* <p>
* This method is deprecated, use getBeanSetWithAnno() instead.
* </p>
*
* @param pkg
* package path
* @param annoClazz
* annotation class
* @return a set of class, or null if error occur,
*/
@Deprecated
public static Set<Class<? extends Object>> getClazzSetWithAnno(String pkg, Class<? extends Annotation> annoClazz) {
// get class set
Set<Class<? extends Object>> clazzSet = new Reflections(pkg).getTypesAnnotatedWith(annoClazz);
// get class set that with a specific annotation
Set<Class<? extends Object>> clazzWithAnnoSet = new HashSet<Class<? extends Object>>();
for (Class<? extends Object> clazz : clazzSet) {
if (clazz.getAnnotation(annoClazz) != null) {
clazzWithAnnoSet.add(clazz);
}
}
return clazzWithAnnoSet;
}
}
junit test:
package eric.j2se.anno;
import java.lang.reflect.Method;
import java.util.Set;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
public class PkgAnnoUtilTest extends TestCase {
private Class<SimpleAnno> annoClazz = SimpleAnno.class; // annotation to filter class,
private String pkg = "eric.j2se.anno.annopkg"; // package name to be search,
private String methodName = "takeAction"; // name of method to execute,
private int annotatedClassCount = 4; // count of class that is annotated,
/**
* test - getBeanSetWithAnno(),
*/
@Test
@SuppressWarnings("unchecked")
public void testGetBeanSetWithAnno() {
System.out.println("------ annotation scan - spring - start ------");
// get classes with in package, and has specified annotation,
Set<BeanDefinition> beanWithAnnoSet = PkgAnnoUtil.getBeanSetWithAnno(new String[] { pkg }, new Class[] { annoClazz });
assertEquals(beanWithAnnoSet.size(), annotatedClassCount);
try {
// execute a specific method,
for (BeanDefinition bean : beanWithAnnoSet) {
Class<? extends Object> clazz = Class.forName(bean.getBeanClassName());
Method md = clazz.getMethod(methodName);
if (md != null) {
md.invoke(clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------ annotation scan - spring - end ------\n");
}
/**
* test - getClazzSetWithAnnoTest(),
*/
@SuppressWarnings("deprecation")
@Test
public void testGetClazzSetWithAnno() {
System.out.println("------ annotation scan - reflections lib - start ------");
// get classes with in package, and has specified annotation,
Set<Class<? extends Object>> clazzWithAnnoSet = PkgAnnoUtil.getClazzSetWithAnno(pkg, annoClazz);
assertEquals(clazzWithAnnoSet.size(), annotatedClassCount);
try {
// execute a specific method,
for (Class<? extends Object> clazz : clazzWithAnnoSet) {
Method md = clazz.getMethod(methodName);
if (md != null) {
md.invoke(clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------ annotation scan - reflections lib - end ------\n");
}
}