package com.test.scaner;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
import eu.infomas.annotation.AnnotationDetector;
import eu.infomas.annotation.AnnotationDetector.Reporter;
import eu.infomas.annotation.AnnotationDetector.TypeReporter;
/**
*
* Created by linjinzhi on 2016/11/18
*
*/
public class AnnotationScanUtils {
private static final Logger log = getLogger(AnnotationScanUtils.class);
private AnnotationScanUtils(){}
private static List<Class<?>> supportAnnotationClasses = new ArrayList<>();//特定注解作用下的类类型列表
private static Map<Class<?>, Class<? extends Annotation>> classesMap = null;//类类型-注解类型映射
/**
* 初始化列表和Map
* @param annotaionType 用户自定义注解类型.
* @param supportAnnotationPackage 注解作用下的类所在包
*/
private static void init(Class<? extends Annotation> annotaionType, String supportAnnotationPackage) {
if(StringUtils.isNotBlank(supportAnnotationPackage)){
String[] sitenameClazzArray = StringUtils.split(supportAnnotationPackage, ";");
classesMap = scan(annotaionType, sitenameClazzArray);
for(Entry<Class<?>, Class<? extends Annotation>> entry : classesMap.entrySet()) {
supportAnnotationClasses.add(entry.getKey());
}
}
}
/**
* 得到特定包下的特定注解作用的Class
* @param annotaionType 要求扫描的注解类型
* @param supportAnnotationPackage 扫描的包名称,如果有多个,则以';'分隔
* @return 被特定注解作用且位于制定包下的所有具体类类型列表
*/
public static List<Class<?>> getSupportClasses(Class<? extends Annotation> annotaionType, String supportAnnotationPackage) {
init(annotaionType, supportAnnotationPackage);
return supportAnnotationClasses;
}
/**
* 得到类类型-注解类型映射
* @return
*/
public static Map<Class<?>, Class<? extends Annotation>> getObjectAnnotationMap(Class<? extends Annotation> annotaionType, String supportAnnotationPackage) {
init(annotaionType, supportAnnotationPackage);
return classesMap;
}
/**
* 扫描类注解.
*
* @param annotationClass
* @param packages
* @return
*/
private static Map<Class<?>, Class<? extends Annotation>> scan(
final Class<? extends Annotation> annotationClass,
String... packages) {
final Map<Class<?>, Class<? extends Annotation>> classesMap = new HashMap<>();
final Reporter reporter = new TypeReporter() {
@SuppressWarnings("unchecked")
@Override
public Class<? extends Annotation>[] annotations() {
return new Class[] { annotationClass };
}
@Override
public void reportTypeAnnotation(
Class<? extends Annotation> annotation, String className) {
try {
classesMap.put(Class.forName(className), annotation);
} catch (ClassNotFoundException e) {
log.error("Class not found: {}", className, e);
}
}
};
startScan(reporter, packages);
return classesMap;
}
private static void startScan(
final AnnotationDetector.Reporter reporter, String... packageNames) {
final AnnotationDetector cf = new AnnotationDetector(reporter);
try {
if (packageNames.length == 0) {
// 解决在web容器下扫描不到类的问题.
URL url = Thread.currentThread().getContextClassLoader()
.getResource("");
File file = new File(url.getPath());
File[] files = file.listFiles(
(File pathname) -> pathname.isDirectory() && !pathname.isHidden()
);
List<String> fileNames = Lists.newLinkedList();
for (File one : files) {
fileNames.add(one.getName());
}
log.debug("san path:{}", fileNames);
cf.detect(fileNames.toArray(new String[fileNames.size()]));
// 这里扫描全部可能会有性能问题
// XXX 在java项目中可以扫描到jar文件中的类,在web项目中不行.
cf.detect();
} else {
cf.detect(packageNames);
}
} catch (IOException e) {
log.error("scan package error packages:{}",
Arrays.toString(packageNames), e);
}
}
/**
* test
* @param args
*/
public static void main(String[] args) {
List<Class<?>> classes = AnnotationScanUtils.getSupportClasses(Crawler.class, "com.test.scaner;");
for(Class<?> clazz : classes) {
System.out.println(clazz);
}
Map<Class<?>, Class<? extends Annotation>> map = AnnotationScanUtils.getObjectAnnotationMap(Crawler.class, "com.test.scaner;");
for(Entry<Class<?>, Class<? extends Annotation>> entry : map.entrySet()) {
System.out.println(entry.getKey()+"\t"+entry.getValue());
}
}
}