mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
!671 修复注解工具类getAnnotations的NPE问题,注解扫描器添新功能
Merge pull request !671 from Createsequence/refactor-annotation
This commit is contained in:
commit
9b19403960
@ -10,13 +10,7 @@ import cn.hutool.core.util.ClassUtil;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.*;
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
@ -157,7 +151,7 @@ public class AnnotationUtil {
|
|||||||
*/
|
*/
|
||||||
public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate<Annotation> predicate) {
|
public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate<Annotation> predicate) {
|
||||||
if (null == annotationEle) {
|
if (null == annotationEle) {
|
||||||
return null;
|
return new Annotation[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isToCombination) {
|
if (isToCombination) {
|
||||||
@ -358,8 +352,8 @@ public class AnnotationUtil {
|
|||||||
/**
|
/**
|
||||||
* 将指定注解实例与其元注解转为合成注解
|
* 将指定注解实例与其元注解转为合成注解
|
||||||
*
|
*
|
||||||
* @param annotation 注解
|
* @param annotation 注解对象
|
||||||
* @param annotationType 注解类型
|
* @param annotationType 注解类
|
||||||
* @param <T> 注解类型
|
* @param <T> 注解类型
|
||||||
* @return 合成注解
|
* @return 合成注解
|
||||||
* @see SyntheticAnnotation
|
* @see SyntheticAnnotation
|
||||||
@ -375,17 +369,17 @@ public class AnnotationUtil {
|
|||||||
* <li>若元素是方法、属性或注解,则只解析其直接声明的注解;</li>
|
* <li>若元素是方法、属性或注解,则只解析其直接声明的注解;</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param annotatedElement 可注解元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @param annotationType 注解类型
|
* @param annotationType 注解类
|
||||||
* @param <T> 注解类型
|
* @param <T> 注解类型
|
||||||
* @return 注解
|
* @return 合成注解
|
||||||
* @see SyntheticAnnotation
|
* @see SyntheticAnnotation
|
||||||
*/
|
*/
|
||||||
public static <T extends Annotation> List<T> getAllSynthesisAnnotations(AnnotatedElement annotatedElement, Class<T> annotationType) {
|
public static <T extends Annotation> List<T> getAllSynthesisAnnotations(AnnotatedElement annotatedEle, Class<T> annotationType) {
|
||||||
AnnotationScanner[] scanners = new AnnotationScanner[] {
|
AnnotationScanner[] scanners = new AnnotationScanner[] {
|
||||||
new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner()
|
new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner()
|
||||||
};
|
};
|
||||||
return AnnotationScanner.scanByAnySupported(annotatedElement, scanners).stream()
|
return AnnotationScanner.scanByAnySupported(annotatedEle, scanners).stream()
|
||||||
.map(SyntheticAnnotation::of)
|
.map(SyntheticAnnotation::of)
|
||||||
.map(annotation -> annotation.getAnnotation(annotationType))
|
.map(annotation -> annotation.getAnnotation(annotationType))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
@ -393,7 +387,58 @@ public class AnnotationUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 方法是否为注解属性方法。 <br />
|
* 扫描注解类,以及注解类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认注解外,
|
||||||
|
* 按元注解对象与{@code annotationType}的距离和{@link Class#getAnnotations()}顺序排序的注解对象集合
|
||||||
|
*
|
||||||
|
* @param annotationType 注解类
|
||||||
|
* @return 注解对象集合
|
||||||
|
* @see MetaAnnotationScanner
|
||||||
|
*/
|
||||||
|
public static List<Annotation> scanMetaAnnotation(Class<? extends Annotation> annotationType) {
|
||||||
|
return new MetaAnnotationScanner().getIfSupport(annotationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>扫描类以及类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外,
|
||||||
|
* 全部类/接口的{@link Class#getAnnotations()}方法返回的注解对象。<br>
|
||||||
|
* 层级结构将按广度优先递归,遵循规则如下:
|
||||||
|
* <ul>
|
||||||
|
* <li>同一层级中,优先处理父类,然后再处理父接口;</li>
|
||||||
|
* <li>同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;</li>
|
||||||
|
* <li>同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;</li>
|
||||||
|
* </ul>
|
||||||
|
* 注解根据其声明类/接口被扫描的顺序排序,若注解都在同一个{@link Class}中被声明,则还会遵循{@link Class#getAnnotations()}的顺序。
|
||||||
|
*
|
||||||
|
* @param targetClass 类
|
||||||
|
* @return 注解对象集合
|
||||||
|
* @see TypeAnnotationScanner
|
||||||
|
*/
|
||||||
|
public static List<Annotation> scanClass(Class<?> targetClass) {
|
||||||
|
return new TypeAnnotationScanner().getIfSupport(targetClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>扫描方法,以及该方法所在类的{@link Class}层级结构中的具有相同方法签名的方法,
|
||||||
|
* 将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外,
|
||||||
|
* 全部匹配方法上{@link Method#getAnnotations()}方法返回的注解对象。<br>
|
||||||
|
* 方法所在类的层级结构将按广度优先递归,遵循规则如下:
|
||||||
|
* <ul>
|
||||||
|
* <li>同一层级中,优先处理父类,然后再处理父接口;</li>
|
||||||
|
* <li>同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;</li>
|
||||||
|
* <li>同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;</li>
|
||||||
|
* </ul>
|
||||||
|
* 方法上的注解根据方法的声明类/接口被扫描的顺序排序,若注解都在同一个类的同一个方法中被声明,则还会遵循{@link Method#getAnnotations()}的顺序。
|
||||||
|
*
|
||||||
|
* @param method 方法
|
||||||
|
* @return 注解对象集合
|
||||||
|
* @see MethodAnnotationScanner
|
||||||
|
*/
|
||||||
|
public static List<Annotation> scanMethod(Method method) {
|
||||||
|
return new MethodAnnotationScanner(true).getIfSupport(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法是否为注解属性方法。 <br>
|
||||||
* 方法无参数,且有返回值的方法认为是注解属性的方法。
|
* 方法无参数,且有返回值的方法认为是注解属性的方法。
|
||||||
*
|
*
|
||||||
* @param method 方法
|
* @param method 方法
|
||||||
|
@ -0,0 +1,276 @@
|
|||||||
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为需要从类的层级结构中获取注解的{@link AnnotationScanner}提供基本实现
|
||||||
|
*
|
||||||
|
* @author huangchengxing
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTypeAnnotationScanner<T extends AbstractTypeAnnotationScanner<T>> implements AnnotationScanner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父类
|
||||||
|
*/
|
||||||
|
// FIXME rename includeSuperClass
|
||||||
|
private boolean includeSupperClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父接口
|
||||||
|
*/
|
||||||
|
private boolean includeInterfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找
|
||||||
|
*/
|
||||||
|
private Predicate<Class<?>> filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除的类型,以上类型及其树结构将直接不被查找
|
||||||
|
*/
|
||||||
|
private final Set<Class<?>> excludeTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换器
|
||||||
|
*/
|
||||||
|
private final List<UnaryOperator<Class<?>>> converters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有转换器
|
||||||
|
*/
|
||||||
|
private boolean hasConverters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前实例
|
||||||
|
*/
|
||||||
|
private final T typedThis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个类注解扫描器
|
||||||
|
*
|
||||||
|
* @param includeSupperClass 是否允许扫描父类
|
||||||
|
* @param includeInterfaces 是否允许扫描父接口
|
||||||
|
* @param filter 过滤器
|
||||||
|
* @param excludeTypes 不包含的类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected AbstractTypeAnnotationScanner(boolean includeSupperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
|
||||||
|
Assert.notNull(filter, "filter must not null");
|
||||||
|
Assert.notNull(excludeTypes, "excludeTypes must not null");
|
||||||
|
this.includeSupperClass = includeSupperClass;
|
||||||
|
this.includeInterfaces = includeInterfaces;
|
||||||
|
this.filter = filter;
|
||||||
|
this.excludeTypes = excludeTypes;
|
||||||
|
this.converters = new ArrayList<>();
|
||||||
|
this.typedThis = (T)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父类
|
||||||
|
*
|
||||||
|
* @return 是否允许扫描父类
|
||||||
|
*/
|
||||||
|
public boolean isIncludeSupperClass() {
|
||||||
|
return includeSupperClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父接口
|
||||||
|
*
|
||||||
|
* @return 是否允许扫描父接口
|
||||||
|
*/
|
||||||
|
public boolean isIncludeInterfaces() {
|
||||||
|
return includeInterfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找
|
||||||
|
*
|
||||||
|
* @param filter 过滤器
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
public T setFilter(Predicate<Class<?>> filter) {
|
||||||
|
Assert.notNull(filter, "filter must not null");
|
||||||
|
this.filter = filter;
|
||||||
|
return typedThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加不扫描的类型,该类型及其树结构将直接不被查找
|
||||||
|
*
|
||||||
|
* @param excludeTypes 不扫描的类型
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
public T addExcludeTypes(Class<?>... excludeTypes) {
|
||||||
|
CollUtil.addAll(this.excludeTypes, excludeTypes);
|
||||||
|
return typedThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加转换器
|
||||||
|
*
|
||||||
|
* @param converter 转换器
|
||||||
|
* @return 当前实例
|
||||||
|
* @see JdkProxyClassConverter
|
||||||
|
*/
|
||||||
|
public T addConverters(UnaryOperator<Class<?>> converter) {
|
||||||
|
Assert.notNull(converter, "converter must not null");
|
||||||
|
this.converters.add(converter);
|
||||||
|
if (!this.hasConverters) {
|
||||||
|
this.hasConverters = CollUtil.isNotEmpty(this.converters);
|
||||||
|
}
|
||||||
|
return typedThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父类
|
||||||
|
*
|
||||||
|
* @param includeSupperClass 是否
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
protected T setIncludeSupperClass(boolean includeSupperClass) {
|
||||||
|
this.includeSupperClass = includeSupperClass;
|
||||||
|
return typedThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许扫描父接口
|
||||||
|
*
|
||||||
|
* @param includeInterfaces 是否
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
protected T setIncludeInterfaces(boolean includeInterfaces) {
|
||||||
|
this.includeInterfaces = includeInterfaces;
|
||||||
|
return typedThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 则根据广度优先递归扫描类的层级结构,并对层级结构中类/接口声明的层级索引和它们声明的注解对象进行处理
|
||||||
|
*
|
||||||
|
* @param consumer 对获取到的注解和注解对应的层级索引的处理
|
||||||
|
* @param annotatedEle 注解元素
|
||||||
|
* @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
|
||||||
|
filter = ObjectUtil.defaultIfNull(filter, annotation -> true);
|
||||||
|
final Class<?> sourceClass = getClassFormAnnotatedElement(annotatedEle);
|
||||||
|
final Deque<List<Class<?>>> classDeque = CollUtil.newLinkedList(CollUtil.newArrayList(sourceClass));
|
||||||
|
final Set<Class<?>> accessedTypes = new LinkedHashSet<>();
|
||||||
|
int index = 0;
|
||||||
|
while (!classDeque.isEmpty()) {
|
||||||
|
final List<Class<?>> currClassQueue = classDeque.removeFirst();
|
||||||
|
final List<Class<?>> nextClassQueue = new ArrayList<>();
|
||||||
|
for (Class<?> targetClass : currClassQueue) {
|
||||||
|
targetClass = convert(targetClass);
|
||||||
|
// 过滤不需要处理的类
|
||||||
|
if (isNotNeedProcess(accessedTypes, targetClass)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
accessedTypes.add(targetClass);
|
||||||
|
// 扫描父类
|
||||||
|
scanSuperClassIfNecessary(nextClassQueue, targetClass);
|
||||||
|
// 扫描接口
|
||||||
|
scanInterfaceIfNecessary(nextClassQueue, targetClass);
|
||||||
|
// 处理层级索引和注解
|
||||||
|
final Annotation[] targetAnnotations = getAnnotationsFromTargetClass(annotatedEle, index, targetClass);
|
||||||
|
for (final Annotation annotation : targetAnnotations) {
|
||||||
|
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) || filter.test(annotation)) {
|
||||||
|
consumer.accept(index, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(nextClassQueue)) {
|
||||||
|
classDeque.addLast(nextClassQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从要搜索的注解元素上获得要递归的类型
|
||||||
|
*
|
||||||
|
* @param annotatedElement 注解元素
|
||||||
|
* @return 要递归的类型
|
||||||
|
*/
|
||||||
|
protected abstract Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedElement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从类上获取最终所需的目标注解
|
||||||
|
*
|
||||||
|
* @param source 最初的注解元素
|
||||||
|
* @param index 类的层级索引
|
||||||
|
* @param targetClass 类
|
||||||
|
* @return 最终所需的目标注解
|
||||||
|
*/
|
||||||
|
protected abstract Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前类是否不需要处理
|
||||||
|
*/
|
||||||
|
protected boolean isNotNeedProcess(Set<Class<?>> accessedTypes, Class<?> targetClass) {
|
||||||
|
return ObjectUtil.isNull(targetClass)
|
||||||
|
|| accessedTypes.contains(targetClass)
|
||||||
|
|| excludeTypes.contains(targetClass)
|
||||||
|
|| filter.negate().test(targetClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若{@link #includeInterfaces}为{@code true},则将目标类的父接口也添加到nextClasses
|
||||||
|
*/
|
||||||
|
protected void scanInterfaceIfNecessary(List<Class<?>> nextClasses, Class<?> targetClass) {
|
||||||
|
if (includeInterfaces) {
|
||||||
|
final Class<?>[] interfaces = targetClass.getInterfaces();
|
||||||
|
if (ArrayUtil.isNotEmpty(interfaces)) {
|
||||||
|
CollUtil.addAll(nextClasses, interfaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若{@link #includeSupperClass}为{@code true},则将目标类的父类也添加到nextClasses
|
||||||
|
*/
|
||||||
|
protected void scanSuperClassIfNecessary(List<Class<?>> nextClassQueue, Class<?> targetClass) {
|
||||||
|
if (includeSupperClass) {
|
||||||
|
final Class<?> superClass = targetClass.getSuperclass();
|
||||||
|
if (!ObjectUtil.equals(superClass, Object.class) && ObjectUtil.isNotNull(superClass)) {
|
||||||
|
nextClassQueue.add(superClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若存在转换器,则使用转换器对目标类进行转换
|
||||||
|
*/
|
||||||
|
protected Class<?> convert(Class<?> target) {
|
||||||
|
if (hasConverters) {
|
||||||
|
for (final UnaryOperator<Class<?>> converter : converters) {
|
||||||
|
target = converter.apply(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若类型为jdk代理类,则尝试转换为原始被代理类
|
||||||
|
*/
|
||||||
|
public static class JdkProxyClassConverter implements UnaryOperator<Class<?>> {
|
||||||
|
@Override
|
||||||
|
public Class<?> apply(Class<?> sourceClass) {
|
||||||
|
return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,17 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -23,66 +27,100 @@ import java.util.stream.Stream;
|
|||||||
public interface AnnotationScanner {
|
public interface AnnotationScanner {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持扫描该可注解元素
|
* 判断是否支持扫描该注解元素
|
||||||
*
|
*
|
||||||
* @param annotatedElement 可注解元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @return 是否支持扫描该可注解元素
|
* @return 是否支持扫描该注解元素
|
||||||
*/
|
*/
|
||||||
default boolean support(AnnotatedElement annotatedElement) {
|
default boolean support(AnnotatedElement annotatedEle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取可注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true
|
* 获取注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true
|
||||||
*
|
*
|
||||||
* @param annotatedElement 可注解元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @return 元素上的注解
|
* @return 注解
|
||||||
*/
|
*/
|
||||||
List<Annotation> getAnnotations(AnnotatedElement annotatedElement);
|
default List<Annotation> getAnnotations(AnnotatedElement annotatedEle) {
|
||||||
|
final List<Annotation> annotations = new ArrayList<>();
|
||||||
|
scan((index, annotation) -> annotations.add(annotation), annotatedEle, null);
|
||||||
|
return annotations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 若{@link #support(AnnotatedElement)}返回{@code true},
|
* 若{@link #support(AnnotatedElement)}返回{@code true},
|
||||||
* 则调用并返回{@link #getAnnotations(AnnotatedElement)}结果,
|
* 则调用并返回{@link #getAnnotations(AnnotatedElement)}结果,
|
||||||
* 否则返回{@link Collections#emptyList()}
|
* 否则返回{@link Collections#emptyList()}
|
||||||
*
|
*
|
||||||
* @param annotatedElement 元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @return 元素上的注解
|
* @return 注解
|
||||||
*/
|
*/
|
||||||
default List<Annotation> getIfSupport(AnnotatedElement annotatedElement) {
|
default List<Annotation> getIfSupport(AnnotatedElement annotatedEle) {
|
||||||
return support(annotatedElement) ? getAnnotations(annotatedElement) : Collections.emptyList();
|
return support(annotatedEle) ? getAnnotations(annotatedEle) : Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描注解元素的层级结构(若存在),然后对获取到的注解和注解对应的层级索引进行处理。
|
||||||
|
* 调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true
|
||||||
|
*
|
||||||
|
* @param consumer 对获取到的注解和注解对应的层级索引的处理
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。
|
||||||
|
*/
|
||||||
|
default void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
|
||||||
|
filter = ObjectUtil.defaultIfNull(filter, annotation -> true);
|
||||||
|
for (final Annotation annotation : annotatedEle.getAnnotations()) {
|
||||||
|
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
|
||||||
|
consumer.accept(0, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若{@link #support(AnnotatedElement)}返回{@code true},则调用{@link #scan(BiConsumer, AnnotatedElement, Predicate)}
|
||||||
|
*
|
||||||
|
* @param consumer 对获取到的注解和注解对应的层级索引的处理
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。
|
||||||
|
*/
|
||||||
|
default void scanIfSupport(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
|
||||||
|
if (support(annotatedEle)) {
|
||||||
|
scan(consumer, annotatedEle, filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 给定一组扫描器,使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解
|
* 给定一组扫描器,使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解
|
||||||
*
|
*
|
||||||
* @param annotatedElement 可注解元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @param scanners 注解扫描器
|
* @param scanners 注解扫描器
|
||||||
* @return 注解
|
* @return 注解
|
||||||
*/
|
*/
|
||||||
static List<Annotation> scanByAnySupported(AnnotatedElement annotatedElement, AnnotationScanner... scanners) {
|
static List<Annotation> scanByAnySupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
|
||||||
if (ObjectUtil.isNull(annotatedElement) && ArrayUtil.isNotEmpty(scanners)) {
|
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return Stream.of(scanners)
|
return Stream.of(scanners)
|
||||||
.filter(scanner -> scanner.support(annotatedElement))
|
.filter(scanner -> scanner.support(annotatedEle))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(scanner -> scanner.getAnnotations(annotatedElement))
|
.map(scanner -> scanner.getAnnotations(annotatedEle))
|
||||||
.orElseGet(Collections::emptyList);
|
.orElseGet(Collections::emptyList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据指定的扫描器,扫描元素上可能存在的注解
|
* 根据指定的扫描器,扫描元素上可能存在的注解
|
||||||
*
|
*
|
||||||
* @param annotatedElement 可注解元素
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @param scanners 注解扫描器
|
* @param scanners 注解扫描器
|
||||||
* @return 注解
|
* @return 注解
|
||||||
*/
|
*/
|
||||||
static List<Annotation> scanByAllScanner(AnnotatedElement annotatedElement, AnnotationScanner... scanners) {
|
static List<Annotation> scanByAllScanner(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
|
||||||
if (ObjectUtil.isNull(annotatedElement) && ArrayUtil.isNotEmpty(scanners)) {
|
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return Stream.of(scanners)
|
return Stream.of(scanners)
|
||||||
.map(scanner -> scanner.getIfSupport(annotatedElement))
|
.map(scanner -> scanner.getIfSupport(annotatedEle))
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扫描{@link Field}上的注解
|
* 扫描{@link Field}上的注解
|
||||||
@ -14,14 +16,32 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class FieldAnnotationScanner implements AnnotationScanner {
|
public class FieldAnnotationScanner implements AnnotationScanner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否支持扫描该注解元素,仅当注解元素是{@link Field}时返回{@code true}
|
||||||
|
*
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return 是否支持扫描该注解元素
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean support(AnnotatedElement annotatedElement) {
|
public boolean support(AnnotatedElement annotatedEle) {
|
||||||
return annotatedElement instanceof Field;
|
return annotatedEle instanceof Field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描{@link Field}上直接声明的注解,调用前需要确保调用{@link #support(AnnotatedElement)}返回为true
|
||||||
|
*
|
||||||
|
* @param consumer 对获取到的注解和注解对应的层级索引的处理
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Annotation> getAnnotations(AnnotatedElement annotatedElement) {
|
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
|
||||||
return CollUtil.newArrayList(annotatedElement.getAnnotations());
|
filter = ObjectUtil.defaultIfNull(filter, annotation -> true);
|
||||||
|
for (final Annotation annotation : annotatedEle.getAnnotations()) {
|
||||||
|
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
|
||||||
|
consumer.accept(0, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ public class MetaAnnotationScanner implements AnnotationScanner {
|
|||||||
private final boolean includeSupperMetaAnnotation;
|
private final boolean includeSupperMetaAnnotation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造一个元注解扫描器
|
||||||
*
|
*
|
||||||
* @param includeSupperMetaAnnotation 获取当前注解的元注解后,是否继续递归扫描的元注解的元注解
|
* @param includeSupperMetaAnnotation 获取当前注解的元注解后,是否继续递归扫描的元注解的元注解
|
||||||
*/
|
*/
|
||||||
@ -46,22 +46,45 @@ public class MetaAnnotationScanner implements AnnotationScanner {
|
|||||||
this(true);
|
this(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否支持扫描该注解元素,仅当注解元素是{@link Annotation}接口的子类{@link Class}时返回{@code true}
|
||||||
|
*
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return 是否支持扫描该注解元素
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean support(AnnotatedElement annotatedElement) {
|
public boolean support(AnnotatedElement annotatedEle) {
|
||||||
return (annotatedElement instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class<?>) annotatedElement));
|
return (annotatedEle instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class<?>)annotatedEle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true
|
||||||
|
*
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return 注解
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Annotation> getAnnotations(AnnotatedElement annotatedEle) {
|
||||||
|
final List<Annotation> annotations = new ArrayList<>();
|
||||||
|
scan(
|
||||||
|
(index, annotation) -> annotations.add(annotation), annotatedEle,
|
||||||
|
annotation -> ObjectUtil.notEqual(annotation, annotatedEle)
|
||||||
|
);
|
||||||
|
return annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按广度优先扫描指定注解上的元注解,对扫描到的注解与层级索引进行操作
|
* 按广度优先扫描指定注解上的元注解,对扫描到的注解与层级索引进行操作
|
||||||
*
|
*
|
||||||
* @param consumer 当前层级索引与操作
|
* @param consumer 当前层级索引与操作
|
||||||
* @param source 源注解
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
* @param filter 过滤器
|
* @param filter 过滤器
|
||||||
* @author huangchengxing
|
|
||||||
*/
|
*/
|
||||||
public void scan(BiConsumer<Integer, Annotation> consumer, Class<? extends Annotation> source, Predicate<Annotation> filter) {
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
|
||||||
filter = ObjectUtil.defaultIfNull(filter, t -> true);
|
filter = ObjectUtil.defaultIfNull(filter, t -> true);
|
||||||
final Deque<List<Class<? extends Annotation>>> deque = CollUtil.newLinkedList(CollUtil.newArrayList(source));
|
final Deque<List<Class<? extends Annotation>>> deque = CollUtil.newLinkedList(CollUtil.newArrayList((Class<? extends Annotation>)annotatedEle));
|
||||||
int distance = 0;
|
int distance = 0;
|
||||||
do {
|
do {
|
||||||
final List<Class<? extends Annotation>> annotationTypes = deque.removeFirst();
|
final List<Class<? extends Annotation>> annotationTypes = deque.removeFirst();
|
||||||
@ -79,16 +102,4 @@ public class MetaAnnotationScanner implements AnnotationScanner {
|
|||||||
} while (includeSupperMetaAnnotation && !deque.isEmpty());
|
} while (includeSupperMetaAnnotation && !deque.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public List<Annotation> getAnnotations(AnnotatedElement annotatedElement) {
|
|
||||||
final List<Annotation> annotations = new ArrayList<>();
|
|
||||||
scan(
|
|
||||||
(index, annotation) -> annotations.add(annotation),
|
|
||||||
(Class<? extends Annotation>) annotatedElement,
|
|
||||||
annotation -> ObjectUtil.notEqual(annotation, annotatedElement)
|
|
||||||
);
|
|
||||||
return annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,121 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扫描{@link Method}上的注解
|
* 扫描{@link Method}上的注解
|
||||||
*
|
*
|
||||||
* @author huangchengxing
|
* @author huangchengxing
|
||||||
*/
|
*/
|
||||||
public class MethodAnnotationScanner implements AnnotationScanner {
|
public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner<MethodAnnotationScanner> implements AnnotationScanner {
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean support(AnnotatedElement annotatedElement) {
|
* 构造一个方法注解扫描器
|
||||||
return annotatedElement instanceof Method;
|
*
|
||||||
|
* @param scanSameSignatureMethod 是否扫描类层级结构中具有相同方法签名的方法
|
||||||
|
* @param filter 过滤器
|
||||||
|
* @param excludeTypes 不包含的类型
|
||||||
|
*/
|
||||||
|
public MethodAnnotationScanner(boolean scanSameSignatureMethod, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
|
||||||
|
super(scanSameSignatureMethod, scanSameSignatureMethod, filter, excludeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个类注解扫描器
|
||||||
|
*
|
||||||
|
* @param scanSameSignatureMethod 是否扫描类层级结构中具有相同方法签名的方法
|
||||||
|
*/
|
||||||
|
public MethodAnnotationScanner(boolean scanSameSignatureMethod) {
|
||||||
|
this(scanSameSignatureMethod, targetClass -> true, CollUtil.newLinkedHashSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个类注解扫描器,仅扫描该方法上直接声明的注解
|
||||||
|
*/
|
||||||
|
public MethodAnnotationScanner() {
|
||||||
|
this(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否支持扫描该注解元素,仅当注解元素是{@link Method}时返回{@code true}
|
||||||
|
*
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return boolean 是否支持扫描该注解元素
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Annotation> getAnnotations(AnnotatedElement annotatedElement) {
|
public boolean support(AnnotatedElement annotatedEle) {
|
||||||
return CollUtil.newArrayList(annotatedElement.getAnnotations());
|
return annotatedEle instanceof Method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取声明该方法的类
|
||||||
|
*
|
||||||
|
* @param annotatedElement 注解元素
|
||||||
|
* @return 要递归的类型
|
||||||
|
* @see Method#getDeclaringClass()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedElement) {
|
||||||
|
return ((Method)annotatedElement).getDeclaringClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 若父类/父接口中方法具有相同的方法签名,则返回该方法上的注解
|
||||||
|
*
|
||||||
|
* @param source 原始方法
|
||||||
|
* @param index 类的层级索引
|
||||||
|
* @param targetClass 类
|
||||||
|
* @return 最终所需的目标注解
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass) {
|
||||||
|
final Method sourceMethod = (Method) source;
|
||||||
|
return Stream.of(targetClass.getDeclaredMethods())
|
||||||
|
.filter(superMethod -> !superMethod.isBridge())
|
||||||
|
.filter(superMethod -> hasSameSignature(sourceMethod, superMethod))
|
||||||
|
.map(AnnotatedElement::getAnnotations)
|
||||||
|
.flatMap(Stream::of)
|
||||||
|
.toArray(Annotation[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否扫描类层级结构中具有相同方法签名的方法
|
||||||
|
*
|
||||||
|
* @param scanSuperMethodIfOverride 是否扫描类层级结构中具有相同方法签名的方法
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
public MethodAnnotationScanner setScanSameSignatureMethod(boolean scanSuperMethodIfOverride) {
|
||||||
|
setIncludeInterfaces(scanSuperMethodIfOverride);
|
||||||
|
setIncludeSupperClass(scanSuperMethodIfOverride);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 该方法是否具备与扫描的方法相同的方法签名
|
||||||
|
*/
|
||||||
|
private boolean hasSameSignature(Method sourceMethod, Method superMethod) {
|
||||||
|
if (false == StrUtil.equals(sourceMethod.getName(), superMethod.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Class<?>[] sourceParameterTypes = sourceMethod.getParameterTypes();
|
||||||
|
final Class<?>[] targetParameterTypes = superMethod.getParameterTypes();
|
||||||
|
if (sourceParameterTypes.length != targetParameterTypes.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ArrayUtil.containsAll(sourceParameterTypes, targetParameterTypes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ClassUtil.isAssignable(superMethod.getReturnType(), sourceMethod.getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,20 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.*;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扫描{@link Class}上的注解
|
* 扫描{@link Class}上的注解
|
||||||
*
|
*
|
||||||
* @author huangchengxing
|
* @author huangchengxing
|
||||||
*/
|
*/
|
||||||
public class TypeAnnotationScanner implements AnnotationScanner {
|
public class TypeAnnotationScanner extends AbstractTypeAnnotationScanner<TypeAnnotationScanner> implements AnnotationScanner {
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否允许扫描父类
|
|
||||||
*/
|
|
||||||
private boolean includeSupperClass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否允许扫描父接口
|
|
||||||
*/
|
|
||||||
private boolean includeInterfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找
|
|
||||||
*/
|
|
||||||
private Predicate<Class<?>> filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排除的类型,以上类型及其树结构将直接不被查找
|
|
||||||
*/
|
|
||||||
private final Set<Class<?>> excludeTypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换器
|
|
||||||
*/
|
|
||||||
private final List<UnaryOperator<Class<?>>> converters;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否有转换器
|
|
||||||
*/
|
|
||||||
private boolean hasConverters;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造一个类注解扫描器
|
* 构造一个类注解扫描器
|
||||||
@ -61,165 +25,80 @@ public class TypeAnnotationScanner implements AnnotationScanner {
|
|||||||
* @param excludeTypes 不包含的类型
|
* @param excludeTypes 不包含的类型
|
||||||
*/
|
*/
|
||||||
public TypeAnnotationScanner(boolean includeSupperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
|
public TypeAnnotationScanner(boolean includeSupperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
|
||||||
Assert.notNull(filter, "filter must not null");
|
super(includeSupperClass, includeInterfaces, filter, excludeTypes);
|
||||||
Assert.notNull(excludeTypes, "excludeTypes must not null");
|
|
||||||
this.includeSupperClass = includeSupperClass;
|
|
||||||
this.includeInterfaces = includeInterfaces;
|
|
||||||
this.filter = filter;
|
|
||||||
this.excludeTypes = excludeTypes;
|
|
||||||
this.converters = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建一个类注解扫描器,默认允许扫描指定元素的父类以及父接口
|
* 构建一个类注解扫描器,默认允许扫描指定元素的父类以及父接口
|
||||||
*/
|
*/
|
||||||
public TypeAnnotationScanner() {
|
public TypeAnnotationScanner() {
|
||||||
this(true, true, t -> true, CollUtil.newHashSet());
|
this(true, true, t -> true, CollUtil.newLinkedHashSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否允许扫描父类
|
* 判断是否支持扫描该注解元素,仅当注解元素是{@link Class}接时返回{@code true}
|
||||||
*
|
*
|
||||||
* @return 是否允许扫描父类
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return 是否支持扫描该注解元素
|
||||||
*/
|
*/
|
||||||
public boolean isIncludeSupperClass() {
|
|
||||||
return includeSupperClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否允许扫描父接口
|
|
||||||
*
|
|
||||||
* @return 是否允许扫描父接口
|
|
||||||
*/
|
|
||||||
public boolean isIncludeInterfaces() {
|
|
||||||
return includeInterfaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找
|
|
||||||
*
|
|
||||||
* @param filter 过滤器
|
|
||||||
* @return 当前实例
|
|
||||||
*/
|
|
||||||
public TypeAnnotationScanner setFilter(Predicate<Class<?>> filter) {
|
|
||||||
Assert.notNull(filter, "filter must not null");
|
|
||||||
this.filter = filter;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加不扫描的类型,该类型及其树结构将直接不被查找
|
|
||||||
*
|
|
||||||
* @param excludeTypes 不扫描的类型
|
|
||||||
* @return 当前实例
|
|
||||||
*/
|
|
||||||
public TypeAnnotationScanner addExcludeTypes(Class<?>... excludeTypes) {
|
|
||||||
CollUtil.addAll(this.excludeTypes, excludeTypes);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加转换器
|
|
||||||
*
|
|
||||||
* @param converter 转换器
|
|
||||||
* @return 当前实例
|
|
||||||
* @see JdkProxyClassConverter
|
|
||||||
*/
|
|
||||||
public TypeAnnotationScanner addConverters(UnaryOperator<Class<?>> converter) {
|
|
||||||
Assert.notNull(converter, "converter must not null");
|
|
||||||
this.converters.add(converter);
|
|
||||||
if (!this.hasConverters) {
|
|
||||||
this.hasConverters = true;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否允许扫描父类
|
|
||||||
*
|
|
||||||
* @param includeSupperClass 是否
|
|
||||||
* @return 当前实例
|
|
||||||
*/
|
|
||||||
public TypeAnnotationScanner setIncludeSupperClass(boolean includeSupperClass) {
|
|
||||||
this.includeSupperClass = includeSupperClass;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否允许扫描父接口
|
|
||||||
*
|
|
||||||
* @param includeInterfaces 是否
|
|
||||||
* @return 当前实例
|
|
||||||
*/
|
|
||||||
public TypeAnnotationScanner setIncludeInterfaces(boolean includeInterfaces) {
|
|
||||||
this.includeInterfaces = includeInterfaces;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean support(AnnotatedElement annotatedElement) {
|
public boolean support(AnnotatedElement annotatedEle) {
|
||||||
return annotatedElement instanceof Class;
|
return annotatedEle instanceof Class;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Annotation> getAnnotations(AnnotatedElement annotatedElement) {
|
|
||||||
return scan((Class<?>) annotatedElement).stream()
|
|
||||||
.map(Class::getAnnotations)
|
|
||||||
.flatMap(Stream::of)
|
|
||||||
.filter(a -> !AnnotationUtil.isJdkMetaAnnotation(a.annotationType()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> convert(Class<?> target) {
|
|
||||||
if (hasConverters) {
|
|
||||||
converters.forEach(c -> c.apply(target));
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归遍历当前类、父类及其实现的父接口
|
* 将注解元素转为{@link Class}
|
||||||
*
|
*
|
||||||
|
* @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
|
||||||
|
* @return 要递归的类型
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedEle) {
|
||||||
|
return (Class<?>)annotatedEle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取{@link Class#getAnnotations()}
|
||||||
|
*
|
||||||
|
* @param source 最初的注解元素
|
||||||
|
* @param index 类的层级索引
|
||||||
* @param targetClass 类
|
* @param targetClass 类
|
||||||
|
* @return 类上直接声明的注解
|
||||||
*/
|
*/
|
||||||
private Set<Class<?>> scan(Class<?> targetClass) {
|
@Override
|
||||||
Deque<Class<?>> classDeque = CollUtil.newLinkedList(targetClass);
|
protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass) {
|
||||||
Set<Class<?>> accessedTypes = new HashSet<>();
|
return targetClass.getAnnotations();
|
||||||
while (!classDeque.isEmpty()) {
|
|
||||||
Class<?> target = convert(classDeque.removeFirst());
|
|
||||||
// 若当前类已经访问过,则无需再次处理
|
|
||||||
if (ObjectUtil.isNull(target) || accessedTypes.contains(target) || excludeTypes.contains(target) || filter.negate().test(target)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
accessedTypes.add(target);
|
|
||||||
|
|
||||||
// 扫描父类
|
|
||||||
if (includeSupperClass) {
|
|
||||||
Class<?> superClass = target.getSuperclass();
|
|
||||||
if (!ObjectUtil.equals(superClass, Object.class) && ObjectUtil.isNotNull(superClass)) {
|
|
||||||
classDeque.addLast(superClass);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扫描接口
|
/**
|
||||||
if (includeInterfaces) {
|
* 是否允许扫描父类
|
||||||
Class<?>[] interfaces = target.getInterfaces();
|
*
|
||||||
if (ArrayUtil.isNotEmpty(interfaces)) {
|
* @param includeSupperClass 是否允许扫描父类
|
||||||
CollUtil.addAll(classDeque, interfaces);
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TypeAnnotationScanner setIncludeSupperClass(boolean includeSupperClass) {
|
||||||
|
return super.setIncludeSupperClass(includeSupperClass);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
return accessedTypes;
|
* 是否允许扫描父接口
|
||||||
|
*
|
||||||
|
* @param includeInterfaces 是否允许扫描父类
|
||||||
|
* @return 当前实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TypeAnnotationScanner setIncludeInterfaces(boolean includeInterfaces) {
|
||||||
|
return super.setIncludeInterfaces(includeInterfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 若类型为jdk代理类,则尝试转换为原始被代理类
|
* 若类型为jdk代理类,则尝试转换为原始被代理类
|
||||||
*/
|
*/
|
||||||
public static class JdkProxyClassConverter implements UnaryOperator<Class<?>> {
|
public static class JdkProxyClassConverter implements UnaryOperator<Class<?>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> apply(Class<?> sourceClass) {
|
public Class<?> apply(Class<?> sourceClass) {
|
||||||
return Proxy.isProxyClass(sourceClass) ? sourceClass.getSuperclass() : sourceClass;
|
return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
package cn.hutool.core.annotation;
|
package cn.hutool.core.annotation;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.*;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AnnotationUtilTest {
|
public class AnnotationUtilTest {
|
||||||
|
|
||||||
@ -46,4 +51,93 @@ public class AnnotationUtilTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanMetaAnnotationTest() {
|
||||||
|
// RootAnnotation -> RootMetaAnnotation1 -> RootMetaAnnotation2 -> RootMetaAnnotation3
|
||||||
|
// -> RootMetaAnnotation3
|
||||||
|
List<Annotation> annotations = AnnotationUtil.scanMetaAnnotation(RootAnnotation.class);
|
||||||
|
Assert.assertEquals(4, annotations.size());
|
||||||
|
Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(0).annotationType());
|
||||||
|
Assert.assertEquals(RootMetaAnnotation1.class, annotations.get(1).annotationType());
|
||||||
|
Assert.assertEquals(RootMetaAnnotation2.class, annotations.get(2).annotationType());
|
||||||
|
Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(3).annotationType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanClassTest() {
|
||||||
|
// TargetClass -> TargetSuperClass ----------------------------------> SuperInterface
|
||||||
|
// -> TargetSuperInterface -> SuperTargetSuperInterface -> SuperInterface
|
||||||
|
List<Annotation> annotations = AnnotationUtil.scanClass(TargetClass.class);
|
||||||
|
Assert.assertEquals(5, annotations.size());
|
||||||
|
Assert.assertEquals("TargetClass", ((AnnotationForTest)annotations.get(0)).value());
|
||||||
|
Assert.assertEquals("TargetSuperClass", ((AnnotationForTest)annotations.get(1)).value());
|
||||||
|
Assert.assertEquals("TargetSuperInterface", ((AnnotationForTest)annotations.get(2)).value());
|
||||||
|
Assert.assertEquals("SuperInterface", ((AnnotationForTest)annotations.get(3)).value());
|
||||||
|
Assert.assertEquals("SuperTargetSuperInterface", ((AnnotationForTest)annotations.get(4)).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanMethodTest() {
|
||||||
|
// TargetClass -> TargetSuperClass
|
||||||
|
// -> TargetSuperInterface
|
||||||
|
Method method = ReflectUtil.getMethod(TargetClass.class, "testMethod");
|
||||||
|
Assert.assertNotNull(method);
|
||||||
|
List<Annotation> annotations = AnnotationUtil.scanMethod(method);
|
||||||
|
Assert.assertEquals(3, annotations.size());
|
||||||
|
Assert.assertEquals("TargetClass", ((AnnotationForTest)annotations.get(0)).value());
|
||||||
|
Assert.assertEquals("TargetSuperClass", ((AnnotationForTest)annotations.get(1)).value());
|
||||||
|
Assert.assertEquals("TargetSuperInterface", ((AnnotationForTest)annotations.get(2)).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface RootMetaAnnotation3 {}
|
||||||
|
|
||||||
|
@RootMetaAnnotation3
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface RootMetaAnnotation2 {}
|
||||||
|
|
||||||
|
@RootMetaAnnotation2
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface RootMetaAnnotation1 {}
|
||||||
|
|
||||||
|
@RootMetaAnnotation3
|
||||||
|
@RootMetaAnnotation1
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE_USE)
|
||||||
|
public @interface RootAnnotation {}
|
||||||
|
|
||||||
|
@AnnotationForTest("TargetClass")
|
||||||
|
static class TargetClass extends TargetSuperClass implements TargetSuperInterface {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@AnnotationForTest("TargetClass")
|
||||||
|
public List<?> testMethod() { return Collections.emptyList(); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnnotationForTest("TargetSuperClass")
|
||||||
|
static class TargetSuperClass implements SuperInterface {
|
||||||
|
|
||||||
|
@AnnotationForTest("TargetSuperClass")
|
||||||
|
public Collection<?> testMethod() { return Collections.emptyList(); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnnotationForTest("TargetSuperInterface")
|
||||||
|
interface TargetSuperInterface extends SuperTargetSuperInterface {
|
||||||
|
|
||||||
|
@AnnotationForTest("TargetSuperInterface")
|
||||||
|
Object testMethod();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnnotationForTest("SuperTargetSuperInterface")
|
||||||
|
interface SuperTargetSuperInterface extends SuperInterface{}
|
||||||
|
|
||||||
|
@AnnotationForTest("SuperInterface")
|
||||||
|
interface SuperInterface{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,5 @@ import java.lang.annotation.Target;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
|
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
|
||||||
@interface AnnotationForScannerTest {
|
@interface AnnotationForScannerTest {
|
||||||
|
String value() default "";
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,25 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author huangchengxing
|
|
||||||
*/
|
|
||||||
public class FieldAnnotationScannerTest {
|
public class FieldAnnotationScannerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFieldAnnotationScanner() {
|
public void supportTest() {
|
||||||
FieldAnnotationScanner scanner = new FieldAnnotationScanner();
|
AnnotationScanner scanner = new FieldAnnotationScanner();
|
||||||
|
Assert.assertTrue(scanner.support(ReflectUtil.getField(Example.class, "id")));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getMethod(Example.class, "getId")));
|
||||||
|
Assert.assertFalse(scanner.support(null));
|
||||||
|
Assert.assertFalse(scanner.support(Example.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAnnotationsTest() {
|
||||||
|
AnnotationScanner scanner = new FieldAnnotationScanner();
|
||||||
Field field = ReflectUtil.getField(Example.class, "id");
|
Field field = ReflectUtil.getField(Example.class, "id");
|
||||||
Assert.assertNotNull(field);
|
Assert.assertNotNull(field);
|
||||||
Assert.assertTrue(scanner.support(field));
|
Assert.assertTrue(scanner.support(field));
|
||||||
@ -25,9 +34,27 @@ public class FieldAnnotationScannerTest {
|
|||||||
Assert.assertEquals(AnnotationForScannerTest.class, CollUtil.getFirst(annotations).annotationType());
|
Assert.assertEquals(AnnotationForScannerTest.class, CollUtil.getFirst(annotations).annotationType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanTest() {
|
||||||
|
AnnotationScanner scanner = new FieldAnnotationScanner();
|
||||||
|
Field field = ReflectUtil.getField(Example.class, "id");
|
||||||
|
Map<Integer, List<Annotation>> map = new HashMap<>();
|
||||||
|
scanner.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
field, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(1, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals(AnnotationForScannerTest.class, map.get(0).get(0).annotationType());
|
||||||
|
}
|
||||||
|
|
||||||
public static class Example {
|
public static class Example {
|
||||||
@AnnotationForScannerTest
|
@AnnotationForScannerTest
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author huangchengxing
|
|
||||||
* @date 2022/06/10 16:51
|
|
||||||
*/
|
|
||||||
public class MateAnnotationScannerTest {
|
public class MateAnnotationScannerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMateAnnotationScanner() {
|
public void supportTest() {
|
||||||
|
AnnotationScanner scanner = new MetaAnnotationScanner();
|
||||||
|
Assert.assertTrue(scanner.support(AnnotationForScannerTest.class));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getField(Example.class, "id")));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getMethod(Example.class, "getId")));
|
||||||
|
Assert.assertFalse(scanner.support(null));
|
||||||
|
Assert.assertFalse(scanner.support(Example.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAnnotationsTest() {
|
||||||
AnnotationScanner scanner = new MetaAnnotationScanner();
|
AnnotationScanner scanner = new MetaAnnotationScanner();
|
||||||
Assert.assertTrue(scanner.support(AnnotationForScannerTest3.class));
|
Assert.assertTrue(scanner.support(AnnotationForScannerTest3.class));
|
||||||
Map<Class<? extends Annotation>, Annotation> annotations = CollUtil.toMap(scanner.getAnnotations(AnnotationForScannerTest3.class), new HashMap<>(), Annotation::annotationType);
|
Map<Class<? extends Annotation>, Annotation> annotations = CollUtil.toMap(scanner.getAnnotations(AnnotationForScannerTest3.class), new HashMap<>(), Annotation::annotationType);
|
||||||
@ -35,8 +44,32 @@ public class MateAnnotationScannerTest {
|
|||||||
Assert.assertFalse(annotations.containsKey(AnnotationForScannerTest3.class));
|
Assert.assertFalse(annotations.containsKey(AnnotationForScannerTest3.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnnotationForScannerTest3
|
@Test
|
||||||
static class Example {}
|
public void scanTest() {
|
||||||
|
AnnotationScanner scanner = new MetaAnnotationScanner();
|
||||||
|
Map<Integer, List<Annotation>> map = new HashMap<>();
|
||||||
|
scanner.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
AnnotationForScannerTest3.class, null
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.assertEquals(3, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals(AnnotationForScannerTest2.class, map.get(0).get(0).annotationType());
|
||||||
|
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals(AnnotationForScannerTest1.class, map.get(1).get(0).annotationType());
|
||||||
|
|
||||||
|
Assert.assertEquals(1, map.get(2).size());
|
||||||
|
Assert.assertEquals(AnnotationForScannerTest.class, map.get(2).get(0).annotationType());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Example {
|
||||||
|
private Integer id;
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AnnotationForScannerTest
|
@AnnotationForScannerTest
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@ -1,35 +1,138 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author huangchengxing
|
|
||||||
*/
|
|
||||||
public class MethodAnnotationScannerTest {
|
public class MethodAnnotationScannerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMethodAnnotationScanner() {
|
public void supportTest() {
|
||||||
|
AnnotationScanner scanner = new MethodAnnotationScanner();
|
||||||
|
Assert.assertTrue(scanner.support(ReflectUtil.getMethod(Example.class, "test")));
|
||||||
|
Assert.assertFalse(scanner.support(null));
|
||||||
|
Assert.assertFalse(scanner.support(Example.class));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getField(Example.class, "id")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAnnotationsTest() {
|
||||||
AnnotationScanner scanner = new MethodAnnotationScanner();
|
AnnotationScanner scanner = new MethodAnnotationScanner();
|
||||||
Method method = ReflectUtil.getMethod(Example.class, "test");
|
Method method = ReflectUtil.getMethod(Example.class, "test");
|
||||||
Assert.assertNotNull(method);
|
Assert.assertNotNull(method);
|
||||||
Assert.assertTrue(scanner.support(method));
|
|
||||||
|
// 不查找父类中具有相同方法签名的方法
|
||||||
List<Annotation> annotations = scanner.getAnnotations(method);
|
List<Annotation> annotations = scanner.getAnnotations(method);
|
||||||
Assert.assertEquals(1, annotations.size());
|
Assert.assertEquals(1, annotations.size());
|
||||||
Assert.assertEquals(CollUtil.getFirst(annotations).annotationType(), AnnotationForScannerTest.class);
|
Assert.assertEquals(CollUtil.getFirst(annotations).annotationType(), AnnotationForScannerTest.class);
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法
|
||||||
|
scanner = new MethodAnnotationScanner(true);
|
||||||
|
annotations = scanner.getAnnotations(method);
|
||||||
|
Assert.assertEquals(3, annotations.size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) annotations.get(0)).value());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) annotations.get(1)).value());
|
||||||
|
Assert.assertEquals("SuperInterface", ((AnnotationForScannerTest) annotations.get(2)).value());
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法,但是不查找SuperInterface
|
||||||
|
scanner = new MethodAnnotationScanner(true).addExcludeTypes(SuperInterface.class);
|
||||||
|
annotations = scanner.getAnnotations(method);
|
||||||
|
Assert.assertEquals(2, annotations.size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) annotations.get(0)).value());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) annotations.get(1)).value());
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法,但是只查找SuperClass
|
||||||
|
scanner = new MethodAnnotationScanner(true)
|
||||||
|
.setFilter(t -> ClassUtil.isAssignable(SuperClass.class, t));
|
||||||
|
annotations = scanner.getAnnotations(method);
|
||||||
|
Assert.assertEquals(2, annotations.size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) annotations.get(0)).value());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) annotations.get(1)).value());
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Example {
|
@Test
|
||||||
@AnnotationForScannerTest
|
public void scanTest() {
|
||||||
public void test() {
|
Method method = ReflectUtil.getMethod(Example.class, "test");
|
||||||
|
|
||||||
|
// 不查找父类中具有相同方法签名的方法
|
||||||
|
Map<Integer, List<Annotation>> map = new HashMap<>();
|
||||||
|
new MethodAnnotationScanner(false).scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
method, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法
|
||||||
|
map.clear();
|
||||||
|
new MethodAnnotationScanner(true).scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
method, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(3, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(2).size());
|
||||||
|
Assert.assertEquals("SuperInterface", ((AnnotationForScannerTest) map.get(2).get(0)).value());
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法,但是不查找SuperInterface
|
||||||
|
map.clear();
|
||||||
|
new MethodAnnotationScanner(true)
|
||||||
|
.addExcludeTypes(SuperInterface.class)
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
method, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(2, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
|
||||||
|
// 查找父类中具有相同方法签名的方法,但是只查找SuperClass
|
||||||
|
map.clear();
|
||||||
|
new MethodAnnotationScanner(true)
|
||||||
|
.setFilter(t -> ClassUtil.isAssignable(SuperClass.class, t))
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
method, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(2, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("SuperClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Example extends SuperClass {
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@AnnotationForScannerTest("Example")
|
||||||
|
public List<?> test() { return Collections.emptyList(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SuperClass implements SuperInterface {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@AnnotationForScannerTest("SuperClass")
|
||||||
|
public Collection<?> test() { return Collections.emptyList(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SuperInterface {
|
||||||
|
|
||||||
|
@AnnotationForScannerTest("SuperInterface")
|
||||||
|
Object test();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,62 +1,141 @@
|
|||||||
package cn.hutool.core.annotation.scanner;
|
package cn.hutool.core.annotation.scanner;
|
||||||
|
|
||||||
import cn.hutool.core.util.ClassUtil;
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author huangchengxing
|
|
||||||
* @date 2022/06/10 16:51
|
|
||||||
*/
|
|
||||||
public class TypeAnnotationScannerTest {
|
public class TypeAnnotationScannerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTypeAnnotationScanner() {
|
public void supportTest() {
|
||||||
AnnotationScanner scanner = new TypeAnnotationScanner();
|
AnnotationScanner scanner = new TypeAnnotationScanner();
|
||||||
Assert.assertTrue(scanner.support(Example.class));
|
Assert.assertTrue(scanner.support(Example.class));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getField(Example.class, "id")));
|
||||||
|
Assert.assertFalse(scanner.support(ReflectUtil.getMethod(Example.class, "getId")));
|
||||||
|
Assert.assertFalse(scanner.support(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAnnotationsTest() {
|
||||||
|
AnnotationScanner scanner = new TypeAnnotationScanner();
|
||||||
List<Annotation> annotations = scanner.getAnnotations(Example.class);
|
List<Annotation> annotations = scanner.getAnnotations(Example.class);
|
||||||
Assert.assertEquals(3, annotations.size());
|
Assert.assertEquals(3, annotations.size());
|
||||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||||
|
|
||||||
// 不查找父接口
|
// 不查找父接口
|
||||||
scanner = new TypeAnnotationScanner().setIncludeInterfaces(false);
|
scanner = new TypeAnnotationScanner().setIncludeInterfaces(false);
|
||||||
Assert.assertTrue(scanner.support(Example.class));
|
|
||||||
annotations = scanner.getAnnotations(Example.class);
|
annotations = scanner.getAnnotations(Example.class);
|
||||||
Assert.assertEquals(2, annotations.size());
|
Assert.assertEquals(2, annotations.size());
|
||||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||||
|
|
||||||
// 不查找父类
|
// 不查找父类
|
||||||
scanner = new TypeAnnotationScanner().setIncludeSupperClass(false);
|
scanner = new TypeAnnotationScanner().setIncludeSupperClass(false);
|
||||||
Assert.assertTrue(scanner.support(Example.class));
|
|
||||||
annotations = scanner.getAnnotations(Example.class);
|
annotations = scanner.getAnnotations(Example.class);
|
||||||
Assert.assertEquals(1, annotations.size());
|
Assert.assertEquals(1, annotations.size());
|
||||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||||
|
|
||||||
// 不查找ExampleSupplerClass.class
|
// 不查找ExampleSupplerClass.class
|
||||||
scanner = new TypeAnnotationScanner().addExcludeTypes(ExampleSupplerClass.class);
|
scanner = new TypeAnnotationScanner().addExcludeTypes(ExampleSupplerClass.class);
|
||||||
Assert.assertTrue(scanner.support(Example.class));
|
|
||||||
annotations = scanner.getAnnotations(Example.class);
|
annotations = scanner.getAnnotations(Example.class);
|
||||||
Assert.assertEquals(1, annotations.size());
|
Assert.assertEquals(1, annotations.size());
|
||||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||||
|
|
||||||
// 只查找ExampleSupplerClass.class
|
// 只查找ExampleSupplerClass.class
|
||||||
scanner = new TypeAnnotationScanner().setFilter(t -> ClassUtil.isAssignable(ExampleSupplerClass.class, t));
|
scanner = new TypeAnnotationScanner().setFilter(t -> ClassUtil.isAssignable(ExampleSupplerClass.class, t));
|
||||||
Assert.assertTrue(scanner.support(Example.class));
|
|
||||||
annotations = scanner.getAnnotations(Example.class);
|
annotations = scanner.getAnnotations(Example.class);
|
||||||
Assert.assertEquals(2, annotations.size());
|
Assert.assertEquals(2, annotations.size());
|
||||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnnotationForScannerTest
|
@Test
|
||||||
|
public void scanTest() {
|
||||||
|
Map<Integer, List<Annotation>> map = new HashMap<>();
|
||||||
|
|
||||||
|
// 查找父类与父接口
|
||||||
|
new TypeAnnotationScanner().scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
Example.class, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(3, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("ExampleSupplerClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(2).size());
|
||||||
|
Assert.assertEquals("ExampleInterface", ((AnnotationForScannerTest) map.get(2).get(0)).value());
|
||||||
|
|
||||||
|
// 不查找父接口
|
||||||
|
map.clear();
|
||||||
|
new TypeAnnotationScanner()
|
||||||
|
.setIncludeInterfaces(false)
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
Example.class, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(2, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("ExampleSupplerClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
|
||||||
|
// 不查找父类
|
||||||
|
map.clear();
|
||||||
|
new TypeAnnotationScanner()
|
||||||
|
.setIncludeSupperClass(false)
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
Example.class, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(1, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
|
||||||
|
// 不查找ExampleSupplerClass.class
|
||||||
|
map.clear();
|
||||||
|
new TypeAnnotationScanner()
|
||||||
|
.addExcludeTypes(ExampleSupplerClass.class)
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
Example.class, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(1, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
|
||||||
|
// 只查找ExampleSupplerClass.class
|
||||||
|
map.clear();
|
||||||
|
new TypeAnnotationScanner()
|
||||||
|
.setFilter(t -> ClassUtil.isAssignable(ExampleSupplerClass.class, t))
|
||||||
|
.scan(
|
||||||
|
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||||
|
Example.class, null
|
||||||
|
);
|
||||||
|
Assert.assertEquals(2, map.size());
|
||||||
|
Assert.assertEquals(1, map.get(0).size());
|
||||||
|
Assert.assertEquals("Example", ((AnnotationForScannerTest) map.get(0).get(0)).value());
|
||||||
|
Assert.assertEquals(1, map.get(1).size());
|
||||||
|
Assert.assertEquals("ExampleSupplerClass", ((AnnotationForScannerTest) map.get(1).get(0)).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnnotationForScannerTest("ExampleSupplerClass")
|
||||||
static class ExampleSupplerClass implements ExampleInterface {}
|
static class ExampleSupplerClass implements ExampleInterface {}
|
||||||
|
|
||||||
@AnnotationForScannerTest
|
@AnnotationForScannerTest("ExampleInterface")
|
||||||
interface ExampleInterface {}
|
interface ExampleInterface {}
|
||||||
|
|
||||||
@AnnotationForScannerTest
|
@AnnotationForScannerTest("Example")
|
||||||
static class Example extends ExampleSupplerClass {}
|
static class Example extends ExampleSupplerClass {
|
||||||
|
private Integer id;
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user