From 96d6c39a14b801406a8e921c0a02477de327fccc Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 15 Sep 2022 13:21:50 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8F=AF=E9=87=8D=E5=A4=8D=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotatedElementUtil.java | 199 +++++++- .../core/annotation/AnnotationUtil.java | 34 +- .../CombinationAnnotationElement.java | 10 +- .../HierarchicalAnnotatedElements.java | 2 +- .../core/annotation/MetaAnnotatedElement.java | 68 +-- .../RepeatableAnnotationCollector.java | 449 ++++++++++++++++++ .../RepeatableMetaAnnotatedElement.java | 387 +++++++++++++++ .../annotation/ResolvedAnnotationMapping.java | 9 +- .../annotation/AnnotatedElementUtilTest.java | 155 ++++++ .../core/annotation/AnnotationUtilTest.java | 24 + .../annotation/MetaAnnotatedElementTest.java | 7 + .../RepeatableAnnotationCollectorTest.java | 220 +++++++++ .../RepeatableMetaAnnotatedElementTest.java | 212 +++++++++ 13 files changed, 1716 insertions(+), 60 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java index 2407de316..62c81f338 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java @@ -93,11 +93,35 @@ import java.util.stream.Stream; * * * + *
可重复注解支持 + *
工具类中格式为findAllXXX或getAllXXX格式的方法, + * 支持获得{@link AnnotatedElement}上的可重复注解。 + * 此处的可重复注解定义包括两方面: + *
扫描{@code element}所处层级结构中的{@link AnnotatedElement},
+ * 并将其全部转为{@link RepeatableMetaAnnotatedElement}后,
+ * 再把所有对象合并为{@link HierarchicalAnnotatedElements}。
+ * 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的直接声明的注解,
+ * 这些注解包含的可重复注解,以及上述注解的所有元注解。
+ *
+ * @param element 元素
+ * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
+ * @return {@link HierarchicalAnnotatedElements}实例
+ * @see #getRepeatableMetaElementCache(AnnotatedElement)
+ * @see #getResolvedRepeatableMetaElementCache(AnnotatedElement)
+ */
+ public static AnnotatedElement toHierarchyRepeatableMetaElement(final AnnotatedElement element, final boolean resolved) {
+ if (Objects.isNull(element)) {
+ return emptyElement();
+ }
+ if (resolved) {
+ return HierarchicalAnnotatedElements.create(element, (es, e) -> getResolvedRepeatableMetaElementCache(e));
+ }
+ return HierarchicalAnnotatedElements.create(element, (es, e) -> getRepeatableMetaElementCache(e));
+ }
+
/**
*
扫描{@code element}所处层级结构中的{@link AnnotatedElement}, * 再把所有对象合并为{@link HierarchicalAnnotatedElements} @@ -460,6 +574,49 @@ public class AnnotatedElementUtil { ); } + /** + * 将{@link AnnotatedElement}转为{@link RepeatableMetaAnnotatedElement}, + * 得到的对象可访问{@link AnnotatedElement}上的直接声明的注解,这些注解包含的可重复注解,以及上述注解的所有元注解。 + * + * @param element 元素 + * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制 + * @return {@link AnnotatedElement}实例 + * @see #getMetaElementCache(AnnotatedElement) + * @see #getResolvedMetaElementCache(AnnotatedElement) + */ + public static AnnotatedElement toRepeatableMetaElement(final AnnotatedElement element, final boolean resolved) { + return ObjUtil.defaultIfNull( + element, e -> resolved ? getResolvedRepeatableMetaElementCache(e) : getRepeatableMetaElementCache(e), emptyElement() + ); + } + + /** + *
将{@link AnnotatedElement}转为{@link RepeatableMetaAnnotatedElement},
+ * 得到的对象可访问{@link AnnotatedElement}上的直接声明的注解,
+ * 通过{@code collector}从这些注解获得的可重复注解,以及上述注解的所有元注解。 当通过静态工厂方法创建时,该实例与关联的{@link ResolvedAnnotationMapping}都会针对{@link ResolvedAnnotationMapping}进行缓存,
- * 从而避免频繁的反射与代理造成不必要的性能损耗。
+ * 在一个{@link MetaAnnotatedElement}中,
+ * {@link AnnotatedElement}上同类型的注解或元注解只会被保留一个,
+ * 即当出现两个根注解都具有相同元注解时,仅有第一个根注解上的元注解会被保留,
+ * 因此当通过{@link #getAnnotationsByType(Class)}
+ * 或{@link #getDeclaredAnnotationsByType(Class)}方法用于只能获得一个注解对象。
*
* @author huangchengxing
* @see ResolvedAnnotationMapping
@@ -214,6 +217,34 @@ public class MetaAnnotatedElement 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
+ * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
+ *
+ * @param annotation 容器注解
+ * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
+ */
+ List 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
+ * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
+ * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
+ *
+ * @param annotation 容器注解
+ * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
+ */
+ @Override
+ public final List 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
+ * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 支持可重复注解的增强{@link AnnotatedElement},
+ * 功能与{@link MetaAnnotatedElement}类似,但是存在下述差异:
+ * Foo.class上注解情况如下:
+ * Super.class上注解情况如下:
+ * Interface.class上注解情况如下:
+ * 注解元素映射,用于包装一个{@link AnnotatedElement},然后将被包装的元素上,
@@ -314,11 +313,15 @@ public class MetaAnnotatedElement 支持可重复注解的增强{@link AnnotatedElement},
@@ -347,11 +346,15 @@ public class RepeatableMetaAnnotatedElement 当注解中有且仅有一个名为{@code value}的属性时,
* 若该属性类型为注解数组,且该数组对应的注解类型被{@link Repeatable}注解,
- * 则收集器将返回该属性中包括的可重复注解。
+ * 则收集器将返回该属性中包括的可重复注解。 当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时,
* 认为该属性包含可重复注解。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
- * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
+ * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
* 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的指定类型注解对象。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
* 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 缓存
+ * 为了避免注解以及{@link AnnotatedElement}层级结构解析过程中的大量反射调用,
+ * 工具类为{@link AnnotatedElement}及其元注解信息进行了缓存。 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。
* 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
+ * 注意:方法将不会通过缓存结果,因此每次调用都需要重新通过反射并获得相关注解。
+ *
+ * @param collector 可重复注解收集器,为{@code null}时等同于{@link RepeatableAnnotationCollector#none()}
+ * @param element 元素
+ * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
+ * @return {@link AnnotatedElement}实例
+ */
+ public static AnnotatedElement toRepeatableMetaElement(
+ final AnnotatedElement element, RepeatableAnnotationCollector collector, final boolean resolved) {
+ if (Objects.isNull(element)) {
+ return emptyElement();
+ }
+ collector = ObjUtil.defaultIfNull(collector, RepeatableAnnotationCollector.none());
+ if (resolved) {
+ return RepeatableMetaAnnotatedElement.create(
+ collector, element, (source, annotation) -> ResolvedAnnotationMapping.create((ResolvedAnnotationMapping)source, annotation, true)
+ );
+ }
+ return RepeatableMetaAnnotatedElement.create(
+ collector, element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source))
+ );
+ }
+
/**
* 将一组注解中的非{@code null}注解对象合并为一个{@link AnnotatedElement}
*
@@ -500,7 +657,7 @@ public class AnnotatedElementUtil {
}
/**
- * 创建一个支持注解解析的{@link MetaAnnotatedElement}
+ * 创建一个不支持注解解析的{@link MetaAnnotatedElement}
*
* @param element {@link AnnotatedElement}
* @return {@link MetaAnnotatedElement}实例
@@ -511,6 +668,30 @@ public class AnnotatedElementUtil {
));
}
+ /**
+ * 创建一个支持注解解析的{@link RepeatableMetaAnnotatedElement}
+ *
+ * @param element {@link AnnotatedElement}
+ * @return {@link MetaAnnotatedElement}实例
+ */
+ private static RepeatableMetaAnnotatedElement
+ * 收集器将返回所有匹配的属性中的可重复注解。
+ *
+ * @param predicate 是否为容纳可重复注解的属性的判断条件
+ * @return {@link RepeatableAnnotationCollector}实例
+ */
+ static RepeatableAnnotationCollector condition(final BiPredicate
+ * 收集器将返回所有符合上述条件的属性中的可重复注解。
+ *
+ * @return {@link RepeatableAnnotationCollector}实例
+ */
+ static RepeatableAnnotationCollector full() {
+ return Full.INSTANCE;
+ }
+
+ /**
+ *
+ * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。
+ *
+ * @param annotation 容器注解
+ * @param accumulate 是否累加
+ * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
+ */
+ List
+ * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。
+ *
+ * @param annotation 容器注解
+ * @param accumulate 是否累加
+ * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
+ */
+ @Override
+ public final List
+ * 收集器将返回所有符合上述条件的属性中的可重复注解。
+ */
+ class Full extends AbstractCollector {
+
+ /**
+ * 默认实例
+ */
+ private static final Full INSTANCE = new Full();
+
+ /**
+ * 空方法缓存
+ */
+ private static final Object NONE = new Object();
+
+ /**
+ * 可重复注解对应的方法缓存
+ */
+ private final Map
+ *
+ * 由于上述机制,当通过实例的{@link #getAnnotation(Class)}或{@link #getDeclaredAnnotation(Class)}
+ * 方法获得指定类型注解时,若该类型注解存在多个,仅能尽可能获得最先被扫描到的那一个。
+ *
+ * @author huangchengxing
+ * @since 6.0.0
+ * @see RepeatableAnnotationCollector
+ */
+public class RepeatableMetaAnnotatedElement
+ * eg:
+ * A上存在注解X,该注解是一个容器注解,内部可重复注解Y,
+ * 包含解析后,得到注解X与可重复注解Y,
+ * 同理,若存在X、Y、X的嵌套关系,则解析后获得全部三者;
+ *
+ * 默认情况下,已经处理过、或在{@link java.lang}包下的注解不会被处理
+ */
+ private boolean isNeedMapping(final Map{@code
+ * annotation3 => annotation2 => annotation1
+ * }
+ *
+ * {@code
+ * annotation4
+ * }
+ *
+ * {@code
+ * annotation6 => annotation5 => annotation6【循环引用】
+ * }
+ */
@Annotation3(value = "foo", num = Integer.MAX_VALUE)
private static class Foo extends Super implements Interface {}
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 5d3612bc8..ebd3cdb44 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,10 +1,12 @@
package cn.hutool.core.annotation;
import cn.hutool.core.util.ObjUtil;
+import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.*;
+import java.lang.reflect.Method;
import java.util.Map;
/**
@@ -12,6 +14,13 @@ import java.util.Map;
*/
public class AnnotationUtilTest {
+ @Test
+ public void testGetDeclaredAnnotations() {
+ Annotation[] annotations = AnnotationUtil.getDeclaredAnnotations(ClassForTest.class);
+ Assert.assertArrayEquals(annotations, ClassForTest.class.getDeclaredAnnotations());
+ Assert.assertSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class));
+ }
+
@Test
public void testToCombination() {
final CombinationAnnotationElement element = AnnotationUtil.toCombination(ClassForTest.class);
@@ -115,6 +124,21 @@ public class AnnotationUtilTest {
Assert.assertEquals(MetaAnnotationForTest.class, annotation.annotationType());
}
+ @Test
+ public void testGetAnnotationAttributes() {
+ Method[] methods = AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class);
+ Assert.assertSame(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class));
+ Assert.assertEquals(1, methods.length);
+ Assert.assertArrayEquals(AnnotationForTest.class.getDeclaredMethods(), methods);
+ }
+
+ @SneakyThrows
+ @Test
+ public void testIsAnnotationAttribute() {
+ Assert.assertFalse(AnnotationUtil.isAnnotationAttribute(AnnotationForTest.class.getMethod("equals", Object.class)));
+ Assert.assertTrue(AnnotationUtil.isAnnotationAttribute(AnnotationForTest.class.getMethod("value")));
+ }
+
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
private @interface MetaAnnotationForTest{
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java
index fd8a2f3cc..f3d780342 100644
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java
@@ -111,6 +111,7 @@ public class MetaAnnotatedElementTest {
new Annotation[]{ annotation4 },
element.getAnnotationsByType(Annotation4.class)
);
+ Assert.assertEquals(0, element.getAnnotationsByType(None.class).length);
}
@Test
@@ -121,6 +122,7 @@ public class MetaAnnotatedElementTest {
new Annotation[]{ annotation4 },
element.getDeclaredAnnotationsByType(Annotation4.class)
);
+ Assert.assertEquals(0, element.getDeclaredAnnotationsByType(None.class).length);
}
@Test
@@ -168,6 +170,11 @@ public class MetaAnnotatedElementTest {
Assert.assertSame(source, element.getElement());
}
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface None { }
+
+ @Annotation4 // 循环引用
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
private @interface Annotation1 {
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java
new file mode 100644
index 000000000..7482d5b55
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java
@@ -0,0 +1,220 @@
+package cn.hutool.core.annotation;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.*;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * test for {@link RepeatableAnnotationCollector}
+ *
+ * @author huangchengxing
+ */
+public class RepeatableAnnotationCollectorTest {
+
+ private static final Annotation1 ANNOTATION1 = Foo.class.getAnnotation(Annotation1.class);
+ private static final List
+ * eg:
+ *
+ * 解析任意{@code Annotation}注解对象,则可以获得{@code value}属性中的{@code Item}注解对象
*
* @return {@link RepeatableAnnotationCollector}实例
* @see Standard
@@ -55,9 +66,19 @@ public interface RepeatableAnnotationCollector {
}
/**
- * 当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时,
+ *
+ * // 容器注解
+ * {@literal @}interface Annotation {
+ * Item[] value() default {};
+ * }
+ * // 可重复注解
+ * {@literal @}Repeatable(Annotation.class)
+ * {@literal @}interface Item {}
+ *
- * 收集器将返回所有符合上述条件的属性中的可重复注解。
+ * 收集器将返回所有符合上述条件的属性中的可重复注解。
+ * eg:
+ *
+ * 解析任意{@code Annotation}注解对象,
+ * 则可以获得{@code items1}属性中的{@code Item1}注解对象,
+ * 以及{@code items2}属性中的{@code Item2}注解对象,
*
* @return {@link RepeatableAnnotationCollector}实例
*/
@@ -67,26 +88,39 @@ public interface RepeatableAnnotationCollector {
/**
*
+ * {@literal @}interface Annotation {
+ * Item1[] items1() default {};
+ * Item2[] items2() default {};
+ * }
+ *
+ * eg:
+ * 若存在嵌套关系{@code a -> b -> c},
+ * 则解析注解a,则将得到全部c注解。
+ * 如果注解不包含可重复注解,则返回a本身。
*
* @param annotation 容器注解
* @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
*/
- List
- * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。
+ * eg:
+ * 若存在嵌套关系{@code a -> b -> c},则解析注解a,
+ * 将获得全部a、b、c注解。
+ * 如果注解不包含可重复注解,则返回a本身。
*
* @param annotation 容器注解
- * @param accumulate 是否累加
* @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
*/
- List
+ * eg:
+ * 若存在嵌套关系{@code a -> b -> c},则:
+ *
+ *
*
* @param annotation 容器注解
* @param annotationType 注解类型
@@ -112,7 +146,7 @@ public interface RepeatableAnnotationCollector {
* @return 空集合
*/
@Override
- public List
* 当{@code accumulate}为{@code true}时,返回结果为全量的注解。
+ * eg:
+ * 若存在嵌套关系{@code a -> b -> c},则解析注解a,
+ * 将获得全部a、b、c注解。
+ * 如果注解不包含可重复注解,则返回其本身。
*
* @param annotation 容器注解
- * @param accumulate 是否累加
* @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
*/
@Override
- public final List
* 接口获取方法和默认方法,获取的方法包括:
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 ebd3cdb44..a1f1eb380 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
@@ -127,7 +127,7 @@ public class AnnotationUtilTest {
@Test
public void testGetAnnotationAttributes() {
Method[] methods = AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class);
- Assert.assertSame(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class));
+ Assert.assertArrayEquals(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class));
Assert.assertEquals(1, methods.length);
Assert.assertArrayEquals(AnnotationForTest.class.getDeclaredMethods(), methods);
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java
index 7322a9a70..5919e66c3 100644
--- a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java
@@ -81,6 +81,18 @@ public class MethodUtilTest {
Assert.assertEquals(10, testClass.getA());
}
+ @Test
+ public void getDeclaredMethodsTest() {
+ Class> type = ReflectUtilTest.TestBenchClass.class;
+ Method[] methods = type.getDeclaredMethods();
+ Assert.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type));
+ Assert.assertSame(MethodUtil.getDeclaredMethods(type), MethodUtil.getDeclaredMethods(type));
+
+ type = Object.class;
+ methods = type.getDeclaredMethods();
+ Assert.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type));
+ }
+
@Test
@Ignore
public void getMethodBenchTest() {
From bf76657b1232161e89cb77f27cfcc4e76f450e09 Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Thu, 22 Sep 2022 09:45:58 +0800
Subject: [PATCH 5/6] fix doc
---
.../core/annotation/RepeatableMetaAnnotatedElement.java | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java
index 1c2894a5d..811307439 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java
@@ -5,7 +5,6 @@ import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import java.lang.annotation.Annotation;
-import java.lang.annotation.Repeatable;
import java.lang.reflect.AnnotatedElement;
import java.util.*;
import java.util.function.BiFunction;
@@ -20,9 +19,9 @@ import java.util.stream.Collectors;
* 即当{@link AnnotatedElement}存在多个根注解有相同的元注解时,这些元注解会都会被扫描到;
*
*
+ * 支持扫描{@link AnnotatedElement}可重复注解,即当当前实例指定的{@link RepeatableAnnotationCollector}
+ * 支持从{@link AnnotatedElement}上直接声明的注解中获得可重复注解时,
+ * 则将会自动将其展开直到不为容器注解为止。
* eg:
* A上存在注解X,该注解是一个容器注解,内部可重复注解Y,
* 包含解析后,得到注解X与可重复注解Y,
From dbbccf3fc8ac172510fc970cb90ed62c8cec366e Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Thu, 22 Sep 2022 14:09:19 +0800
Subject: [PATCH 6/6] =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=B7=A5=E5=85=B7?=
=?UTF-8?q?=E7=B1=BB=E6=94=AF=E6=8C=81=E4=B8=BB=E5=8A=A8=E6=B8=85=E7=A9=BA?=
=?UTF-8?q?=E7=BC=93=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/annotation/AnnotatedElementUtil.java | 38 ++++++++++++++++---
.../core/annotation/AnnotationUtil.java | 7 ++++
.../RepeatableAnnotationCollector.java | 8 ++++
.../annotation/AnnotatedElementUtilTest.java | 25 ++++++++++++
.../core/annotation/AnnotationUtilTest.java | 3 ++
5 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java
index 62c81f338..34ee2974b 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java
@@ -103,8 +103,8 @@ import java.util.stream.Stream;
* 该属性类型为注解数组,且数组中注解被{@link java.lang.annotation.Repeatable}注解,
* 则认为被包括的注解为可重复注解;
* eg:
- * A上存在注解X,该注解是一个容器注解,内部可重复注解Y,
- * 包含解析后,得到注解X与它包含的可重复注解Y;
+ * A上存在注解X,该注解是一个容器注解,内部包含可重复注解Y,
+ * 解析X后,得到注解X与它包含的可重复注解Y;
*
+ * 缓存功能默认基于{@link WeakConcurrentMap}实现,会在gc时自动回收部分缓存数据。
+ * 但是若有必要,也可以调用{@link #clearCaches()}方法主动清空缓存。
+ *
* @author huangchengxing
* @see ResolvedAnnotationMapping
* @see GenericAnnotationMapping
@@ -650,7 +656,7 @@ public class AnnotatedElementUtil {
* @param element {@link AnnotatedElement}
* @return {@link MetaAnnotatedElement}实例
*/
- private static MetaAnnotatedElement
+ *
+ *
+ * @see AnnotationUtil#clearCaches()
+ * @see RepeatableAnnotationCollector#clearSingletonCaches()
+ */
+ public static void clearCaches() {
+ ELEMENT_CACHE.clear();
+ RESOLVED_ELEMENT_CACHE.clear();
+ REPEATABLE_ELEMENT_CACHE.clear();
+ RESOLVED_REPEATABLE_ELEMENT_CACHE.clear();
+ RepeatableAnnotationCollector.clearSingletonCaches();
+ AnnotationUtil.clearCaches();
+ }
+
/**
* 由一组注解聚合来的{@link AnnotatedElement}
*/
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 b5dd123c5..6691928d6 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
@@ -354,4 +354,11 @@ public class AnnotationUtil {
&& !attribute.isSynthetic();
}
+ /**
+ * 清空相关缓存
+ */
+ public static void clearCaches() {
+ DECLARED_ANNOTATIONS_CACHE.clear();
+ }
+
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java
index 1daae6cdb..cf6fe2bed 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java
@@ -86,6 +86,14 @@ public interface RepeatableAnnotationCollector {
return Full.INSTANCE;
}
+ /**
+ * 清空单例缓存
+ */
+ static void clearSingletonCaches() {
+ Standard.INSTANCE.repeatableMethodCache.clear();
+ Full.INSTANCE.repeatableMethodCache.clear();
+ }
+
/**
*
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java
index 5585b657e..7445efde8 100644
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java
@@ -37,6 +37,31 @@ public class AnnotatedElementUtilTest {
ANNOTATION6, ANNOTATION5 // Interface.class's annotations
};
+ @Test
+ public void testClearCaches() {
+ AnnotatedElement type = Foo.class;
+
+ AnnotatedElement element = AnnotatedElementUtil.getResolvedMetaElementCache(type);
+ Assert.assertSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type));
+ AnnotatedElementUtil.clearCaches();
+ Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type));
+
+ element = AnnotatedElementUtil.getMetaElementCache(type);
+ Assert.assertSame(element, AnnotatedElementUtil.getMetaElementCache(type));
+ AnnotatedElementUtil.clearCaches();
+ Assert.assertNotSame(element, AnnotatedElementUtil.getMetaElementCache(type));
+
+ element = AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type);
+ Assert.assertSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type));
+ AnnotatedElementUtil.clearCaches();
+ Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type));
+
+ element = AnnotatedElementUtil.getRepeatableMetaElementCache(type);
+ Assert.assertSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type));
+ AnnotatedElementUtil.clearCaches();
+ Assert.assertNotSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type));
+ }
+
@Test
public void testIsAnnotated() {
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation1.class));
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 a1f1eb380..6053d8851 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
@@ -19,6 +19,9 @@ public class AnnotationUtilTest {
Annotation[] annotations = AnnotationUtil.getDeclaredAnnotations(ClassForTest.class);
Assert.assertArrayEquals(annotations, ClassForTest.class.getDeclaredAnnotations());
Assert.assertSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class));
+
+ AnnotationUtil.clearCaches();
+ Assert.assertNotSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class));
}
@Test