From d1bba67d3a3c43b736458e22f0dcfb7c283fe25e Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:25:24 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=BD=9C=E5=9C=A8?= =?UTF-8?q?=E7=9A=84=E7=A9=BA=E6=8C=87=E9=92=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/core/annotation/AnnotationUtil.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index f765ffa2b..0fee2867c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -10,13 +10,7 @@ import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; -import java.lang.annotation.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.annotation.*; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -157,7 +151,7 @@ public class AnnotationUtil { */ public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate predicate) { if (null == annotationEle) { - return null; + return new Annotation[0]; } if (isToCombination) { From 062ec707f28fd4e036736d77b0b6817fa31cd3ff Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:28:36 +0800 Subject: [PATCH 2/6] =?UTF-8?q?AnnotationScanner=E6=B7=BB=E5=8A=A0scan?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8CMethodAnnotationScanner=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=99=A8=E6=B7=BB=E5=8A=A0=E5=AF=B9=E7=88=B6=E7=B1=BB?= =?UTF-8?q?/=E7=88=B6=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95=E4=B8=AD?= =?UTF-8?q?=E5=85=B7=E6=9C=89=E7=9B=B8=E5=90=8C=E7=AD=BE=E5=90=8D=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E6=89=AB=E6=8F=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractTypeAnnotationScanner.java | 276 ++++++++++++++++++ .../annotation/scanner/AnnotationScanner.java | 60 +++- .../scanner/FieldAnnotationScanner.java | 28 +- .../scanner/MetaAnnotationScanner.java | 50 ++-- .../scanner/MethodAnnotationScanner.java | 103 ++++++- .../scanner/TypeAnnotationScanner.java | 181 ++---------- 6 files changed, 510 insertions(+), 188 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/scanner/AbstractTypeAnnotationScanner.java 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; } } From 0b60b24950546a2e1e716f94a2eea8286a8d413a Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:30:41 +0800 Subject: [PATCH 3/6] =?UTF-8?q?test:=20=E6=B3=A8=E8=A7=A3=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=99=A8=E7=9A=84=E5=AE=8C=E5=96=84=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scanner/AnnotationForScannerTest.java | 2 +- .../scanner/FieldAnnotationScannerTest.java | 37 +++++- .../scanner/MateAnnotationScannerTest.java | 47 ++++++- .../scanner/MethodAnnotationScannerTest.java | 123 ++++++++++++++++-- .../scanner/TypeAnnotationScannerTest.java | 105 +++++++++++++-- 5 files changed, 278 insertions(+), 36 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/AnnotationForScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/AnnotationForScannerTest.java index d032a516b..c6fab4ddb 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/AnnotationForScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/AnnotationForScannerTest.java @@ -11,5 +11,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) @interface AnnotationForScannerTest { - + String value() default ""; } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/FieldAnnotationScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/FieldAnnotationScannerTest.java index 59af613bd..e9881b234 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/FieldAnnotationScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/FieldAnnotationScannerTest.java @@ -7,16 +7,25 @@ import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** - * @author huangchengxing - */ public class FieldAnnotationScannerTest { @Test - public void testFieldAnnotationScanner() { - FieldAnnotationScanner scanner = new FieldAnnotationScanner(); + public void supportTest() { + 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"); Assert.assertNotNull(field); Assert.assertTrue(scanner.support(field)); @@ -25,9 +34,27 @@ public class FieldAnnotationScannerTest { Assert.assertEquals(AnnotationForScannerTest.class, CollUtil.getFirst(annotations).annotationType()); } + @Test + public void scanTest() { + AnnotationScanner scanner = new FieldAnnotationScanner(); + Field field = ReflectUtil.getField(Example.class, "id"); + Map> 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 { @AnnotationForScannerTest private Integer id; + + public Integer getId() { + return id; + } } } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MateAnnotationScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MateAnnotationScannerTest.java index 1b36181fe..780edd62a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MateAnnotationScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MateAnnotationScannerTest.java @@ -1,21 +1,30 @@ package cn.hutool.core.annotation.scanner; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; import org.junit.Assert; import org.junit.Test; import java.lang.annotation.*; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; -/** - * @author huangchengxing - * @date 2022/06/10 16:51 - */ public class MateAnnotationScannerTest { @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(); Assert.assertTrue(scanner.support(AnnotationForScannerTest3.class)); Map, 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)); } - @AnnotationForScannerTest3 - static class Example {} + @Test + public void scanTest() { + AnnotationScanner scanner = new MetaAnnotationScanner(); + Map> 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 @Retention(RetentionPolicy.RUNTIME) diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MethodAnnotationScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MethodAnnotationScannerTest.java index 25798c84d..1ccde3908 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MethodAnnotationScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/MethodAnnotationScannerTest.java @@ -1,35 +1,138 @@ package cn.hutool.core.annotation.scanner; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ReflectUtil; import org.junit.Assert; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.List; +import java.util.*; -/** - * @author huangchengxing - */ public class MethodAnnotationScannerTest { @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(); Method method = ReflectUtil.getMethod(Example.class, "test"); Assert.assertNotNull(method); - Assert.assertTrue(scanner.support(method)); + + // 不查找父类中具有相同方法签名的方法 List annotations = scanner.getAnnotations(method); Assert.assertEquals(1, annotations.size()); 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 { - @AnnotationForScannerTest - public void test() { + @Test + public void scanTest() { + Method method = ReflectUtil.getMethod(Example.class, "test"); + + // 不查找父类中具有相同方法签名的方法 + Map> 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(); - } } } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java index 1df0727d1..0b3f31f81 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java @@ -1,62 +1,141 @@ package cn.hutool.core.annotation.scanner; import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; import org.junit.Assert; import org.junit.Test; import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** - * @author huangchengxing - * @date 2022/06/10 16:51 - */ public class TypeAnnotationScannerTest { @Test - public void testTypeAnnotationScanner() { + public void supportTest() { AnnotationScanner scanner = new TypeAnnotationScanner(); 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 annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(3, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); // 不查找父接口 scanner = new TypeAnnotationScanner().setIncludeInterfaces(false); - Assert.assertTrue(scanner.support(Example.class)); annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(2, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); // 不查找父类 scanner = new TypeAnnotationScanner().setIncludeSupperClass(false); - Assert.assertTrue(scanner.support(Example.class)); annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(1, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); // 不查找ExampleSupplerClass.class scanner = new TypeAnnotationScanner().addExcludeTypes(ExampleSupplerClass.class); - Assert.assertTrue(scanner.support(Example.class)); annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(1, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); // 只查找ExampleSupplerClass.class scanner = new TypeAnnotationScanner().setFilter(t -> ClassUtil.isAssignable(ExampleSupplerClass.class, t)); - Assert.assertTrue(scanner.support(Example.class)); annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(2, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); } - @AnnotationForScannerTest + @Test + public void scanTest() { + Map> 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 {} - @AnnotationForScannerTest + @AnnotationForScannerTest("ExampleInterface") interface ExampleInterface {} - @AnnotationForScannerTest - static class Example extends ExampleSupplerClass {} + @AnnotationForScannerTest("Example") + static class Example extends ExampleSupplerClass { + private Integer id; + public Integer getId() { + return id; + } + } } From 7cc09949423ac8e3efa9d859fc7f5603382cd8db Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:31:38 +0800 Subject: [PATCH 4/6] =?UTF-8?q?AnnotationUtil=E6=B7=BB=E5=8A=A0scanMetaAnn?= =?UTF-8?q?otation=E3=80=81scanClass=E4=B8=8EscanMethod=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotationUtil.java | 91 ++++++++++++++---- .../core/annotation/AnnotationUtilTest.java | 96 ++++++++++++++++++- 2 files changed, 166 insertions(+), 21 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index 0fee2867c..14d160864 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -130,7 +130,7 @@ public class AnnotationUtil { */ public static T[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Class annotationType) { final Annotation[] annotations = getAnnotations(annotationEle, isToCombination, - (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass()))); + (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass()))); final T[] result = ArrayUtil.newArray(annotationType, annotations.length); for (int i = 0; i < annotations.length; i++) { @@ -151,7 +151,7 @@ public class AnnotationUtil { */ public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate predicate) { if (null == annotationEle) { - return new Annotation[0]; + return null; } if (isToCombination) { @@ -251,8 +251,8 @@ public class AnnotationUtil { final String name = t.getName(); // 跳过自有的几个方法 return (false == "hashCode".equals(name)) // - && (false == "toString".equals(name)) // - && (false == "annotationType".equals(name)); + && (false == "toString".equals(name)) // + && (false == "annotationType".equals(name)); } return false; }); @@ -288,13 +288,13 @@ public class AnnotationUtil { final Target target = annotationType.getAnnotation(Target.class); if (null == target) { return new ElementType[]{ElementType.TYPE, // - ElementType.FIELD, // - ElementType.METHOD, // - ElementType.PARAMETER, // - ElementType.CONSTRUCTOR, // - ElementType.LOCAL_VARIABLE, // - ElementType.ANNOTATION_TYPE, // - ElementType.PACKAGE// + ElementType.FIELD, // + ElementType.METHOD, // + ElementType.PARAMETER, // + ElementType.CONSTRUCTOR, // + ElementType.LOCAL_VARIABLE, // + ElementType.ANNOTATION_TYPE, // + ElementType.PACKAGE// }; } return target.value(); @@ -352,9 +352,9 @@ public class AnnotationUtil { /** * 将指定注解实例与其元注解转为合成注解 * - * @param annotation 注解 - * @param annotationType 注解类型 - * @param 注解类型 + * @param annotation 注解对象 + * @param annotationType 注解类 + * @param 注解类型 * @return 合成注解 * @see SyntheticAnnotation */ @@ -369,23 +369,74 @@ public class AnnotationUtil { *
  • 若元素是方法、属性或注解,则只解析其直接声明的注解;
  • * * - * @param annotatedElement 可注解元素 - * @param annotationType 注解类型 - * @param 注解类型 - * @return 注解 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param annotationType 注解类 + * @param 注解类型 + * @return 合成注解 * @see SyntheticAnnotation */ - public static List getAllSynthesisAnnotations(AnnotatedElement annotatedElement, Class annotationType) { + public static List getAllSynthesisAnnotations(AnnotatedElement annotatedEle, Class annotationType) { AnnotationScanner[] scanners = new AnnotationScanner[] { new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner() }; - return AnnotationScanner.scanByAnySupported(annotatedElement, scanners).stream() + return AnnotationScanner.scanByAnySupported(annotatedEle, scanners).stream() .map(SyntheticAnnotation::of) .map(annotation -> annotation.getAnnotation(annotationType)) .filter(Objects::nonNull) .collect(Collectors.toList()); } + /** + * 扫描注解类,以及注解类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认注解外, + * 按元注解对象与{@code annotationType}的距离和{@link Class#getAnnotations()}顺序排序的注解对象集合 + * + * @param annotationType 注解类 + * @return 注解对象集合 + * @see MetaAnnotationScanner + */ + public static List scanMetaAnnotation(Class annotationType) { + return new MetaAnnotationScanner().getIfSupport(annotationType); + } + + /** + *

    扫描类以及类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外, + * 全部类/接口的{@link Class#getAnnotations()}方法返回的注解对象。
    + * 层级结构将按广度优先递归,遵循规则如下: + *

      + *
    • 同一层级中,优先处理父类,然后再处理父接口;
    • + *
    • 同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;
    • + *
    • 同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;
    • + *
    + * 注解根据其声明类/接口被扫描的顺序排序,若注解都在同一个{@link Class}中被声明,则还会遵循{@link Class#getAnnotations()}的顺序。 + * + * @param targetClass 类 + * @return 注解对象集合 + * @see TypeAnnotationScanner + */ + public static List scanClass(Class targetClass) { + return new TypeAnnotationScanner().getIfSupport(targetClass); + } + + /** + *

    扫描方法,以及该方法所在类的{@link Class}层级结构中的具有相同方法签名的方法, + * 将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外, + * 全部匹配方法上{@link Method#getAnnotations()}方法返回的注解对象。
    + * 方法所在类的层级结构将按广度优先递归,遵循规则如下: + *

      + *
    • 同一层级中,优先处理父类,然后再处理父接口;
    • + *
    • 同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;
    • + *
    • 同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;
    • + *
    + * 方法上的注解根据方法的声明类/接口被扫描的顺序排序,若注解都在同一个类的同一个方法中被声明,则还会遵循{@link Method#getAnnotations()}的顺序。 + * + * @param method 方法 + * @return 注解对象集合 + * @see MethodAnnotationScanner + */ + public static List scanMethod(Method method) { + return new MethodAnnotationScanner(true).getIfSupport(method); + } + /** * 方法是否为注解属性方法。
    * 方法无参数,且有返回值的方法认为是注解属性的方法。 diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index 167b62d2c..a47fc9712 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -1,9 +1,14 @@ package cn.hutool.core.annotation; +import cn.hutool.core.util.ReflectUtil; import org.junit.Assert; 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 { @@ -46,4 +51,93 @@ public class AnnotationUtilTest { } } + + @Test + public void scanMetaAnnotationTest() { + // RootAnnotation -> RootMetaAnnotation1 -> RootMetaAnnotation2 -> RootMetaAnnotation3 + // -> RootMetaAnnotation3 + List 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 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 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{} + } From 8cf30150757bddea9fb2ead0aabcecd3a7790757 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:34:16 +0800 Subject: [PATCH 5/6] fix comment --- .../core/annotation/AnnotationUtil.java | 4 +- .../AbstractTypeAnnotationScanner.java | 12 ++-- .../annotation/scanner/AnnotationScanner.java | 60 +++++++++---------- .../scanner/FieldAnnotationScanner.java | 16 ++--- .../scanner/MetaAnnotationScanner.java | 25 ++++---- .../scanner/MethodAnnotationScanner.java | 17 +++--- .../scanner/TypeAnnotationScanner.java | 20 +++---- 7 files changed, 75 insertions(+), 79 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index 14d160864..4c1bb3354 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -151,7 +151,7 @@ public class AnnotationUtil { */ public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate predicate) { if (null == annotationEle) { - return null; + return new Annotation[0]; } if (isToCombination) { @@ -438,7 +438,7 @@ public class AnnotationUtil { } /** - * 方法是否为注解属性方法。
    + * 方法是否为注解属性方法。
    * 方法无参数,且有返回值的方法认为是注解属性的方法。 * * @param method 方法 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 index 84559716e..28de9831a 100644 --- 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 @@ -159,14 +159,14 @@ public abstract class AbstractTypeAnnotationScanner consumer, AnnotatedElement annotatedElement, Predicate filter) { + public void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, annotation -> true); - final Class sourceClass = getClassFormAnnotatedElement(annotatedElement); + final Class sourceClass = getClassFormAnnotatedElement(annotatedEle); final Deque>> classDeque = CollUtil.newLinkedList(CollUtil.newArrayList(sourceClass)); final Set> accessedTypes = new LinkedHashSet<>(); int index = 0; @@ -185,7 +185,7 @@ public abstract class AbstractTypeAnnotationScanner getAnnotations(AnnotatedElement annotatedElement) { + default List getAnnotations(AnnotatedElement annotatedEle) { final List annotations = new ArrayList<>(); - scan((index, annotation) -> annotations.add(annotation), annotatedElement, null); + scan((index, annotation) -> annotations.add(annotation), annotatedEle, null); return annotations; } @@ -53,24 +53,24 @@ public interface AnnotationScanner { * 则调用并返回{@link #getAnnotations(AnnotatedElement)}结果, * 否则返回{@link Collections#emptyList()} * - * @param annotatedElement 注解元素 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission * @return 注解 */ - default List getIfSupport(AnnotatedElement annotatedElement) { - return support(annotatedElement) ? getAnnotations(annotatedElement) : Collections.emptyList(); + default List getIfSupport(AnnotatedElement annotatedEle) { + return support(annotatedEle) ? getAnnotations(annotatedEle) : Collections.emptyList(); } /** * 扫描注解元素的层级结构(若存在),然后对获取到的注解和注解对应的层级索引进行处理。 * 调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true * - * @param consumer 对获取到的注解和注解对应的层级索引的处理 - * @param annotatedElement 注解元素 - * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + * @param consumer 对获取到的注解和注解对应的层级索引的处理 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 */ - default void scan(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + default void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, annotation -> true); - for (Annotation annotation : annotatedElement.getAnnotations()) { + for (Annotation annotation : annotatedEle.getAnnotations()) { if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) { consumer.accept(0, annotation); } @@ -80,47 +80,47 @@ public interface AnnotationScanner { /** * 若{@link #support(AnnotatedElement)}返回{@code true},则调用{@link #scan(BiConsumer, AnnotatedElement, Predicate)} * - * @param consumer 对获取到的注解和注解对应的层级索引的处理 - * @param annotatedElement 注解元素 - * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + * @param consumer 对获取到的注解和注解对应的层级索引的处理 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 */ - default void scanIfSupport(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { - if (support(annotatedElement)) { - scan(consumer, annotatedElement, filter); + default void scanIfSupport(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { + if (support(annotatedEle)) { + scan(consumer, annotatedEle, filter); } } /** * 给定一组扫描器,使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解 * - * @param annotatedElement 注解元素 - * @param scanners 注解扫描器 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param scanners 注解扫描器 * @return 注解 */ - static List scanByAnySupported(AnnotatedElement annotatedElement, AnnotationScanner... scanners) { - if (ObjectUtil.isNull(annotatedElement) && ArrayUtil.isNotEmpty(scanners)) { + static List scanByAnySupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) { + if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) { return Collections.emptyList(); } return Stream.of(scanners) - .filter(scanner -> scanner.support(annotatedElement)) + .filter(scanner -> scanner.support(annotatedEle)) .findFirst() - .map(scanner -> scanner.getAnnotations(annotatedElement)) + .map(scanner -> scanner.getAnnotations(annotatedEle)) .orElseGet(Collections::emptyList); } /** * 根据指定的扫描器,扫描元素上可能存在的注解 * - * @param annotatedElement 注解元素 - * @param scanners 注解扫描器 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param scanners 注解扫描器 * @return 注解 */ - static List scanByAllScanner(AnnotatedElement annotatedElement, AnnotationScanner... scanners) { - if (ObjectUtil.isNull(annotatedElement) && ArrayUtil.isNotEmpty(scanners)) { + static List scanByAllScanner(AnnotatedElement annotatedEle, AnnotationScanner... scanners) { + if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) { return Collections.emptyList(); } return Stream.of(scanners) - .map(scanner -> scanner.getIfSupport(annotatedElement)) + .map(scanner -> scanner.getIfSupport(annotatedEle)) .flatMap(Collection::stream) .collect(Collectors.toList()); } 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 fcd4c45fe..413a49e3f 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 @@ -19,25 +19,25 @@ public class FieldAnnotationScanner implements AnnotationScanner { /** * 判断是否支持扫描该注解元素,仅当注解元素是{@link Field}时返回{@code true} * - * @param annotatedElement 注解元素 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission * @return 是否支持扫描该注解元素 */ @Override - public boolean support(AnnotatedElement annotatedElement) { - return annotatedElement instanceof Field; + public boolean support(AnnotatedElement annotatedEle) { + return annotatedEle instanceof Field; } /** * 扫描{@link Field}上直接声明的注解,调用前需要确保调用{@link #support(AnnotatedElement)}返回为true * - * @param consumer 对获取到的注解和注解对应的层级索引的处理 - * @param annotatedElement 注解元素 - * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 + * @param consumer 对获取到的注解和注解对应的层级索引的处理 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param filter 注解过滤器,无法通过过滤器的注解不会被处理。该参数允许为空。 */ @Override - public void scan(BiConsumer consumer, AnnotatedElement annotatedElement, Predicate filter) { + public void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, annotation -> true); - for (Annotation annotation : annotatedElement.getAnnotations()) { + for (Annotation annotation : annotatedEle.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 02b44b412..98cc08a0e 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 @@ -49,27 +49,26 @@ public class MetaAnnotationScanner implements AnnotationScanner { /** * 判断是否支持扫描该注解元素,仅当注解元素是{@link Annotation}接口的子类{@link Class}时返回{@code true} * - * @param annotatedElement 注解元素 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission * @return 是否支持扫描该注解元素 */ @Override - public boolean support(AnnotatedElement annotatedElement) { - return (annotatedElement instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class) annotatedElement)); + public boolean support(AnnotatedElement annotatedEle) { + return (annotatedEle instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class)annotatedEle)); } /** * 获取注解元素上的全部注解。调用该方法前,需要确保调用{@link #support(AnnotatedElement)}返回为true * - * @param annotatedElement 注解元素 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission * @return 注解 */ @Override - public List getAnnotations(AnnotatedElement annotatedElement) { + public List getAnnotations(AnnotatedElement annotatedEle) { final List annotations = new ArrayList<>(); scan( - (index, annotation) -> annotations.add(annotation), - annotatedElement, - annotation -> ObjectUtil.notEqual(annotation, annotatedElement) + (index, annotation) -> annotations.add(annotation), annotatedEle, + annotation -> ObjectUtil.notEqual(annotation, annotatedEle) ); return annotations; } @@ -77,15 +76,15 @@ public class MetaAnnotationScanner implements AnnotationScanner { /** * 按广度优先扫描指定注解上的元注解,对扫描到的注解与层级索引进行操作 * - * @param consumer 当前层级索引与操作 - * @param source 源注解 - * @param filter 过滤器 + * @param consumer 当前层级索引与操作 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param filter 过滤器 */ @SuppressWarnings("unchecked") @Override - public void scan(BiConsumer consumer, AnnotatedElement source, Predicate filter) { + public void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, t -> true); - final Deque>> deque = CollUtil.newLinkedList(CollUtil.newArrayList((Class)source)); + final Deque>> deque = CollUtil.newLinkedList(CollUtil.newArrayList((Class)annotatedEle)); int distance = 0; do { final List> annotationTypes = deque.removeFirst(); 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 67f847780..d55ff1c58 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 @@ -49,21 +49,19 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner - * @author huangchengxing - * @date 2022/6/29 17:21 + * @return 要递归的类型 * @see Method#getDeclaringClass() */ @Override @@ -74,9 +72,10 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner targetClass) { @@ -92,7 +91,7 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner getClassFormAnnotatedElement(AnnotatedElement annotatedElement) { - return (Class)annotatedElement; + protected Class getClassFormAnnotatedElement(AnnotatedElement annotatedEle) { + return (Class)annotatedEle; } /** @@ -73,7 +73,7 @@ public class TypeAnnotationScanner extends AbstractTypeAnnotationScanner> { @Override public Class apply(Class sourceClass) { From 10f3abfeb8109f904615c850b0269cbbf7276daf Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:38:11 +0800 Subject: [PATCH 6/6] fix code --- .../annotation/scanner/AbstractTypeAnnotationScanner.java | 2 +- .../hutool/core/annotation/scanner/AnnotationScanner.java | 2 +- .../core/annotation/scanner/FieldAnnotationScanner.java | 2 +- .../core/annotation/scanner/MetaAnnotationScanner.java | 4 ++-- .../core/annotation/scanner/MethodAnnotationScanner.java | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) 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 index 28de9831a..39a4841ef 100644 --- 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 @@ -256,7 +256,7 @@ public abstract class AbstractTypeAnnotationScanner convert(Class target) { if (hasConverters) { - for (UnaryOperator> converter : converters) { + for (final UnaryOperator> converter : converters) { target = converter.apply(target); } } 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 3e789fa54..7874b72d6 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 @@ -70,7 +70,7 @@ public interface AnnotationScanner { */ default void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, annotation -> true); - for (Annotation annotation : annotatedEle.getAnnotations()) { + for (final Annotation annotation : annotatedEle.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/FieldAnnotationScanner.java b/hutool-core/src/main/java/cn/hutool/core/annotation/scanner/FieldAnnotationScanner.java index 413a49e3f..8357fd834 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 @@ -37,7 +37,7 @@ public class FieldAnnotationScanner implements AnnotationScanner { @Override public void scan(BiConsumer consumer, AnnotatedElement annotatedEle, Predicate filter) { filter = ObjectUtil.defaultIfNull(filter, annotation -> true); - for (Annotation annotation : annotatedEle.getAnnotations()) { + for (final Annotation annotation : annotatedEle.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 98cc08a0e..22886d047 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 @@ -67,8 +67,8 @@ public class MetaAnnotationScanner implements AnnotationScanner { public List getAnnotations(AnnotatedElement annotatedEle) { final List annotations = new ArrayList<>(); scan( - (index, annotation) -> annotations.add(annotation), annotatedEle, - annotation -> ObjectUtil.notEqual(annotation, annotatedEle) + (index, annotation) -> annotations.add(annotation), annotatedEle, + annotation -> ObjectUtil.notEqual(annotation, annotatedEle) ); 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 d55ff1c58..8202c8d80 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 @@ -79,7 +79,7 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner targetClass) { - Method sourceMethod = (Method) source; + final Method sourceMethod = (Method) source; return Stream.of(targetClass.getDeclaredMethods()) .filter(superMethod -> !superMethod.isBridge()) .filter(superMethod -> hasSameSignature(sourceMethod, superMethod)) @@ -104,11 +104,11 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner[] sourceParameterTypes = sourceMethod.getParameterTypes(); - Class[] targetParameterTypes = superMethod.getParameterTypes(); + final Class[] sourceParameterTypes = sourceMethod.getParameterTypes(); + final Class[] targetParameterTypes = superMethod.getParameterTypes(); if (sourceParameterTypes.length != targetParameterTypes.length) { return false; }