diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AbstractTypeAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AbstractTypeAnnotationScanner.java new file mode 100644 index 000000000..84559716e --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AbstractTypeAnnotationScanner.java @@ -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> implements AnnotationScanner { + + /** + * 是否允许扫描父类 + */ + // FIXME rename includeSuperClass + private boolean includeSupperClass; + + /** + * 是否允许扫描父接口 + */ + private boolean includeInterfaces; + + /** + * 过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找 + */ + private Predicate> filter; + + /** + * 排除的类型,以上类型及其树结构将直接不被查找 + */ + private final Set> excludeTypes; + + /** + * 转换器 + */ + private final List>> 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> filter, Set> 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> 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> 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 annotatedElement 注解元素 + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + */ + @Override + public void scan(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + filter = ObjectUtil.defaultIfNull(filter, annotation -> true); + final Class sourceClass = getClassFormAnnotatedElement(annotatedElement); + final Deque>> classDeque = CollUtil.newLinkedList(CollUtil.newArrayList(sourceClass)); + final Set> accessedTypes = new LinkedHashSet<>(); + int index = 0; + while (!classDeque.isEmpty()) { + final List> currClassQueue = classDeque.removeFirst(); + final List> 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(annotatedElement, 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> 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> 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> 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 (UnaryOperator> converter : converters) { + target = converter.apply(target); + } + } + return target; + } + + /** + * 若类型为jdk代理类,则尝试转换为原始被代理类 + */ + public static class JdkProxyClassConverter implements UnaryOperator> { + @Override + public Class apply(Class sourceClass) { + return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass; + } + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AnnotationScanner.java index bf49978ff..79192931c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AnnotationScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AnnotationScanner.java @@ -1,13 +1,17 @@ package cn.hutool.core.annotation.scanner; +import cn.hutool.core.annotation.AnnotationUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -23,39 +27,73 @@ import java.util.stream.Stream; public interface AnnotationScanner { /** - * 是否支持扫描该可注解元素 + * 判断是否支持扫描该注解元素 * - * @param annotatedElement 可注解元素 - * @return 是否支持扫描该可注解元素 + * @param annotatedElement 注解元素 + * @return 是否支持扫描该注解元素 */ default boolean support(AnnotatedElement annotatedElement) { return false; } /** - * 获取可注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true + * 获取注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true * - * @param annotatedElement 可注解元素 - * @return 元素上的注解 + * @param annotatedElement 注解元素 + * @return 注解 */ - List getAnnotations(AnnotatedElement annotatedElement); + default List getAnnotations(AnnotatedElement annotatedElement) { + final List annotations = new ArrayList<>(); + scan((index, annotation) -> annotations.add(annotation), annotatedElement, null); + return annotations; + } /** * 若{@link #support(AnnotatedElement)}返回{@code true}, * 则调用并返回{@link #getAnnotations(AnnotatedElement)}结果, * 否则返回{@link Collections#emptyList()} * - * @param annotatedElement 元素 - * @return 元素上的注解 + * @param annotatedElement 注解元素 + * @return 注解 */ default List getIfSupport(AnnotatedElement annotatedElement) { return support(annotatedElement) ? getAnnotations(annotatedElement) : Collections.emptyList(); } + /** + * 扫描注解元素的层级结构(若存在),然后对获取到的注解和注解对应的层级索引进行处理。 + * 调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true + * + * @param consumer 对获取到的注解和注解对应的层级索引的处理 + * @param annotatedElement 注解元素 + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + */ + default void scan(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + filter = ObjectUtil.defaultIfNull(filter, annotation -> true); + for (Annotation annotation : annotatedElement.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 annotatedElement 注解元素 + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + */ + default void scanIfSupport(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + if (support(annotatedElement)) { + scan(consumer, annotatedElement, filter); + } + } + /** * 给定一组扫描器,使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解 * - * @param annotatedElement 可注解元素 + * @param annotatedElement 注解元素 * @param scanners 注解扫描器 * @return 注解 */ @@ -73,7 +111,7 @@ public interface AnnotationScanner { /** * 根据指定的扫描器,扫描元素上可能存在的注解 * - * @param annotatedElement 可注解元素 + * @param annotatedElement 注解元素 * @param scanners 注解扫描器 * @return 注解 */ diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/FieldAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/FieldAnnotationScanner.java index 119c51ecb..fcd4c45fe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/FieldAnnotationScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/FieldAnnotationScanner.java @@ -1,11 +1,13 @@ 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.reflect.AnnotatedElement; import java.lang.reflect.Field; -import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Predicate; /** * 扫描{@link Field}上的注解 @@ -14,14 +16,32 @@ import java.util.List; */ public class FieldAnnotationScanner implements AnnotationScanner { + /** + * 判断是否支持扫描该注解元素,仅当注解元素是{@link Field}时返回{@code true} + * + * @param annotatedElement 注解元素 + * @return 是否支持扫描该注解元素 + */ @Override public boolean support(AnnotatedElement annotatedElement) { return annotatedElement instanceof Field; } + /** + * 扫描{@link Field}上直接声明的注解,调用前需要确保调用{@link #support(AnnotatedElement)}返回为true + * + * @param consumer 对获取到的注解和注解对应的层级索引的处理 + * @param annotatedElement 注解元素 + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + */ @Override - public List getAnnotations(AnnotatedElement annotatedElement) { - return CollUtil.newArrayList(annotatedElement.getAnnotations()); + public void scan(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + filter = ObjectUtil.defaultIfNull(filter, annotation -> true); + for (Annotation annotation : annotatedElement.getAnnotations()) { + if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) { + consumer.accept(0, annotation); + } + } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MetaAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MetaAnnotationScanner.java index bbb036f31..02b44b412 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MetaAnnotationScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MetaAnnotationScanner.java @@ -31,7 +31,7 @@ public class MetaAnnotationScanner implements AnnotationScanner { private final boolean includeSupperMetaAnnotation; /** - * 构造 + * 构造一个元注解扫描器 * * @param includeSupperMetaAnnotation 获取当前注解的元注解后,是否继续递归扫描的元注解的元注解 */ @@ -46,30 +46,54 @@ public class MetaAnnotationScanner implements AnnotationScanner { this(true); } + /** + * 判断是否支持扫描该注解元素,仅当注解元素是{@link Annotation}接口的子类{@link Class}时返回{@code true} + * + * @param annotatedElement 注解元素 + * @return 是否支持扫描该注解元素 + */ @Override public boolean support(AnnotatedElement annotatedElement) { return (annotatedElement instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class) annotatedElement)); } + /** + * 获取注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true + * + * @param annotatedElement 注解元素 + * @return 注解 + */ + @Override + public List getAnnotations(AnnotatedElement annotatedElement) { + final List annotations = new ArrayList<>(); + scan( + (index, annotation) -> annotations.add(annotation), + annotatedElement, + annotation -> ObjectUtil.notEqual(annotation, annotatedElement) + ); + return annotations; + } + /** * 按广度优先扫描指定注解上的元注解,对扫描到的注解与层级索引进行操作 * * @param consumer 当前层级索引与操作 * @param source 源注解 * @param filter 过滤器 - * @author huangchengxing */ - public void scan(BiConsumer consumer, Class source, Predicate filter) { + @SuppressWarnings("unchecked") + @Override + public void scan(BiConsumer consumer, AnnotatedElement source, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, t -> true); - final Deque>> deque = CollUtil.newLinkedList(CollUtil.newArrayList(source)); + final Deque>> deque = CollUtil.newLinkedList(CollUtil.newArrayList((Class)source)); int distance = 0; do { final List> annotationTypes = deque.removeFirst(); for (final Class type : annotationTypes) { final List metaAnnotations = Stream.of(type.getAnnotations()) - .filter(a -> !AnnotationUtil.isJdkMetaAnnotation(a.annotationType())) - .filter(filter) - .collect(Collectors.toList()); + .filter(a -> !AnnotationUtil.isJdkMetaAnnotation(a.annotationType())) + .filter(filter) + .collect(Collectors.toList()); for (final Annotation metaAnnotation : metaAnnotations) { consumer.accept(distance, metaAnnotation); } @@ -79,16 +103,4 @@ public class MetaAnnotationScanner implements AnnotationScanner { } while (includeSupperMetaAnnotation && !deque.isEmpty()); } - @SuppressWarnings("unchecked") - @Override - public List getAnnotations(AnnotatedElement annotatedElement) { - final List annotations = new ArrayList<>(); - scan( - (index, annotation) -> annotations.add(annotation), - (Class) annotatedElement, - annotation -> ObjectUtil.notEqual(annotation, annotatedElement) - ); - return annotations; - } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MethodAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MethodAnnotationScanner.java index f8de322b8..67f847780 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MethodAnnotationScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/MethodAnnotationScanner.java @@ -1,27 +1,122 @@ package cn.hutool.core.annotation.scanner; 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.reflect.AnnotatedElement; 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}上的注解 * * @author huangchengxing */ -public class MethodAnnotationScanner implements AnnotationScanner { +public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner implements AnnotationScanner { + /** + * 构造一个方法注解扫描器 + * + * @param scanSameSignatureMethod 是否扫描类层级结构中具有相同方法签名的方法 + * @param filter 过滤器 + * @param excludeTypes 不包含的类型 + */ + public MethodAnnotationScanner(boolean scanSameSignatureMethod, Predicate> filter, Set> 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 annotatedElement 注解元素 + * @return boolean 是否支持扫描该注解元素 + */ @Override public boolean support(AnnotatedElement annotatedElement) { return annotatedElement instanceof Method; } + /** + * 获取声明该方法的类 + * + * @param annotatedElement 注解元素 + * @return java.lang.Class + * @author huangchengxing + * @date 2022/6/29 17:21 + * @see Method#getDeclaringClass() + */ @Override - public List getAnnotations(AnnotatedElement annotatedElement) { - return CollUtil.newArrayList(annotatedElement.getAnnotations()); + protected Class getClassFormAnnotatedElement(AnnotatedElement annotatedElement) { + return ((Method)annotatedElement).getDeclaringClass(); + } + + /** + * 若父类/父接口中方法具有相同的方法签名,则返回该方法上的注解 + * + * @param source 原始方法 + * @param index 类的层级索引 + * @param targetClass 类 + */ + @Override + protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class targetClass) { + 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 (!StrUtil.equals(sourceMethod.getName(), superMethod.getName())) { + return false; + } + Class[] sourceParameterTypes = sourceMethod.getParameterTypes(); + 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()); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/TypeAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/TypeAnnotationScanner.java index 76066b412..b8dfa7d57 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/TypeAnnotationScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/TypeAnnotationScanner.java @@ -1,56 +1,20 @@ 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.Set; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * 扫描{@link Class}上的注解 * * @author huangchengxing */ -public class TypeAnnotationScanner implements AnnotationScanner { - - /** - * 是否允许扫描父类 - */ - private boolean includeSupperClass; - - /** - * 是否允许扫描父接口 - */ - private boolean includeInterfaces; - - /** - * 过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找 - */ - private Predicate> filter; - - /** - * 排除的类型,以上类型及其树结构将直接不被查找 - */ - private final Set> excludeTypes; - - /** - * 转换器 - */ - private final List>> converters; - - /** - * 是否有转换器 - */ - private boolean hasConverters; +public class TypeAnnotationScanner extends AbstractTypeAnnotationScanner implements AnnotationScanner { /** * 构造一个类注解扫描器 @@ -61,77 +25,49 @@ public class TypeAnnotationScanner implements AnnotationScanner { * @param excludeTypes 不包含的类型 */ public TypeAnnotationScanner(boolean includeSupperClass, boolean includeInterfaces, Predicate> filter, Set> 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<>(); + super(includeSupperClass, includeInterfaces, filter, excludeTypes); } /** * 构建一个类注解扫描器,默认允许扫描指定元素的父类以及父接口 */ public TypeAnnotationScanner() { - this(true, true, t -> true, CollUtil.newHashSet()); + this(true, true, t -> true, CollUtil.newLinkedHashSet()); } /** - * 是否允许扫描父类 + * 判断是否支持扫描该注解元素,仅当注解元素是{@link Class}接时返回{@code true} * - * @return 是否允许扫描父类 + * @param annotatedElement 注解元素 + * @return 是否支持扫描该注解元素 */ - public boolean isIncludeSupperClass() { - return includeSupperClass; + @Override + public boolean support(AnnotatedElement annotatedElement) { + return annotatedElement instanceof Class; } /** - * 是否允许扫描父接口 + * 将注解元素转为{@link Class} * - * @return 是否允许扫描父接口 + * @param annotatedElement 注解元素 + * @return 类 */ - public boolean isIncludeInterfaces() { - return includeInterfaces; + @Override + protected Class getClassFormAnnotatedElement(AnnotatedElement annotatedElement) { + return (Class)annotatedElement; } /** - * 设置过滤器,若类型无法通过该过滤器,则该类型及其树结构将直接不被查找 + * 获取{@link Class#getAnnotations()} * - * @param filter 过滤器 - * @return 当前实例 + * @param source 最初的注解元素 + * @param index 类的层级索引 + * @param targetClass 类 + * @return 类上直接声明的注解 */ - public TypeAnnotationScanner setFilter(Predicate> 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> converter) { - Assert.notNull(converter, "converter must not null"); - this.converters.add(converter); - if (!this.hasConverters) { - this.hasConverters = true; - } - return this; + @Override + protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class targetClass) { + return targetClass.getAnnotations(); } /** @@ -140,9 +76,9 @@ public class TypeAnnotationScanner implements AnnotationScanner { * @param includeSupperClass 是否 * @return 当前实例 */ + @Override public TypeAnnotationScanner setIncludeSupperClass(boolean includeSupperClass) { - this.includeSupperClass = includeSupperClass; - return this; + return super.setIncludeSupperClass(includeSupperClass); } /** @@ -151,75 +87,20 @@ public class TypeAnnotationScanner implements AnnotationScanner { * @param includeInterfaces 是否 * @return 当前实例 */ + @Override public TypeAnnotationScanner setIncludeInterfaces(boolean includeInterfaces) { - this.includeInterfaces = includeInterfaces; - return this; - } - - @Override - public boolean support(AnnotatedElement annotatedElement) { - return annotatedElement instanceof Class; - } - - @Override - public List 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; - } - - /** - * 递归遍历当前类、父类及其实现的父接口 - * - * @param targetClass 类 - */ - private Set> scan(Class targetClass) { - Deque> classDeque = CollUtil.newLinkedList(targetClass); - Set> accessedTypes = new HashSet<>(); - 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)) { - CollUtil.addAll(classDeque, interfaces); - } - } - } - return accessedTypes; + return super.setIncludeInterfaces(includeInterfaces); } /** * 若类型为jdk代理类,则尝试转换为原始被代理类 + * @deprecated replace with {@link AbstractTypeAnnotationScanner.JdkProxyClassConverter} */ + @Deprecated public static class JdkProxyClassConverter implements UnaryOperator> { - @Override public Class apply(Class sourceClass) { - return Proxy.isProxyClass(sourceClass) ? sourceClass.getSuperclass() : sourceClass; + return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass; } }