欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Scan classes with specified annotation under specified package

程序员文章站 2022-06-05 18:21:48
...

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