annotationType) {
+ return toMetaElement(element, true)
+ .getDeclaredAnnotation(annotationType);
+ }
+
+ /**
+ * 从{@code element}上,获取所有的注解。
+ * 得到的注解支持基于{@link Alias}的别名机制。
+ *
+ * @param element {@link AnnotatedElement}
+ * @return 注解对象
+ */
+ public static Annotation[] getDirectlyResolvedAnnotations(final AnnotatedElement element) {
+ return toMetaElement(element, true)
+ .getDeclaredAnnotations();
+ }
+
+ // endregion
+
+ // region ========== to element ==========
+
+ /**
+ * 扫描{@code element}所处层级结构中的{@link AnnotatedElement},
+ * 并将其全部转为{@link MetaAnnotatedElement}后,
+ * 再把所有对象合并为{@link HierarchicalAnnotatedElements}。
+ * 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的注解及元注解。
+ *
+ * @param element 元素
+ * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
+ * @return {@link HierarchicalAnnotatedElements}实例
+ * @see #getMetaElementCache(AnnotatedElement)
+ * @see #getResolvedMetaElementCache(AnnotatedElement)
+ */
+ public static AnnotatedElement toHierarchyMetaElement(final AnnotatedElement element, final boolean resolved) {
+ if (Objects.isNull(element)) {
+ return emptyElement();
+ }
+ if (resolved) {
+ return HierarchicalAnnotatedElements.create(element, (es, e) -> getResolvedMetaElementCache(e));
+ }
+ return HierarchicalAnnotatedElements.create(element, (es, e) -> getMetaElementCache(e));
+ }
+
+ /**
+ *
扫描{@code element}所处层级结构中的{@link AnnotatedElement},
+ * 再把所有对象合并为{@link HierarchicalAnnotatedElements}
+ * 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的注解。
+ *
+ * @param element 元素
+ * @return {@link AnnotatedElement}实例
+ */
+ public static AnnotatedElement toHierarchyElement(final AnnotatedElement element) {
+ return ObjUtil.defaultIfNull(
+ element, ele -> HierarchicalAnnotatedElements.create(ele, (es, e) -> e), emptyElement()
+ );
+ }
+
+ /**
+ * 将{@link AnnotatedElement}转为{@link MetaAnnotatedElement},
+ * 得到的对象可访问{@code element}上所有的注解及元注解。
+ *
+ * @param element 元素
+ * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
+ * @return {@link AnnotatedElement}实例
+ * @see #getMetaElementCache(AnnotatedElement)
+ * @see #getResolvedMetaElementCache(AnnotatedElement)
+ */
+ public static AnnotatedElement toMetaElement(final AnnotatedElement element, final boolean resolved) {
+ return ObjUtil.defaultIfNull(
+ element, e -> resolved ? getResolvedMetaElementCache(e) : getMetaElementCache(e), emptyElement()
+ );
+ }
+
+ /**
+ * 将一组注解中的非{@code null}注解对象合并为一个{@link AnnotatedElement}
+ *
+ * @param annotations 注解
+ * @return {@link AnnotatedElement}实例
+ * @see ConstantElement
+ */
+ public static AnnotatedElement asElement(Annotation... annotations) {
+ annotations = ArrayUtil.filter(annotations, Objects::nonNull);
+ return ArrayUtil.isEmpty(annotations) ?
+ emptyElement() : new ConstantElement(annotations);
+ }
+
+ /**
+ * 获取一个不包含任何注解的{@link AnnotatedElement}
+ *
+ * @return {@link AnnotatedElement}实例
+ * @see EmptyElement
+ */
+ public static AnnotatedElement emptyElement() {
+ return EmptyElement.INSTANCE;
+ }
+
+ // endregion
+
+ // region ========== private ==========
+
+ /**
+ * 创建一个支持注解解析的{@link MetaAnnotatedElement}
+ *
+ * @param element {@link AnnotatedElement}
+ * @return {@link MetaAnnotatedElement}实例
+ */
+ private static MetaAnnotatedElement getResolvedMetaElementCache(final AnnotatedElement element) {
+ return RESOLVED_ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
+ element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true)
+ ));
+ }
+
+ /**
+ * 创建一个支持注解解析的{@link MetaAnnotatedElement}
+ *
+ * @param element {@link AnnotatedElement}
+ * @return {@link MetaAnnotatedElement}实例
+ */
+ private static MetaAnnotatedElement getMetaElementCache(final AnnotatedElement element) {
+ return ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
+ element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source))
+ ));
+ }
+
+ // endregion
+
+ /**
+ * 由一组注解聚合来的{@link AnnotatedElement}
+ */
+ private static class ConstantElement implements AnnotatedElement {
+
+ /**
+ * 注解对象
+ */
+ private final Annotation[] annotations;
+
+ /**
+ * 构造
+ *
+ * @param annotations 注解
+ */
+ ConstantElement(final Annotation[] annotations) {
+ this.annotations = Objects.requireNonNull(annotations);
+ }
+
+ /**
+ * 获取指定类型的注解对象
+ *
+ * @param annotationClass 注解类型
+ * @param 注解类型
+ * @return 注解
+ */
+ @Override
+ public T getAnnotation(final Class annotationClass) {
+ return Stream.of(annotations)
+ .filter(annotation -> Objects.equals(annotation.annotationType(), annotationClass))
+ .findFirst()
+ .map(annotationClass::cast)
+ .orElse(null);
+ }
+
+ /**
+ * 获取指定直接所有的注解对象
+ *
+ * @return 注解
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return annotations.clone();
+ }
+
+ /**
+ * 获取指定直接声明的注解对象
+ *
+ * @return 注解
+ */
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return annotations.clone();
+ }
+ }
+
+ /**
+ * 不包含任何注解的{@link AnnotatedElement}
+ */
+ private static class EmptyElement implements AnnotatedElement {
+
+ /**
+ * 默认的空实例
+ */
+ static final EmptyElement INSTANCE = new EmptyElement();
+
+ /**
+ * 固定返回{@code null}
+ *
+ * @param annotationClass 注解类型
+ * @param 注解类型
+ * @return {@code null}
+ */
+ @Override
+ public T getAnnotation(final Class annotationClass) {
+ return null;
+ }
+
+ /**
+ * 固定返回空数组
+ *
+ * @return 空数组
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return new Annotation[0];
+ }
+
+ /**
+ * 固定返回空数组
+ *
+ * @return 空数组
+ */
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return new Annotation[0];
+ }
+ }
+
+}
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
new file mode 100644
index 000000000..03ed704a6
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java
@@ -0,0 +1,480 @@
+package cn.hutool.core.annotation;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.*;
+import java.lang.reflect.AnnotatedElement;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * test for {@link AnnotatedElementUtil}
+ *
+ * @author huangchengxing
+ */
+public class AnnotatedElementUtilTest {
+
+ private final static Annotation3 ANNOTATION3 = Foo.class.getAnnotation(Annotation3.class); // Foo.class's annotations
+ private final static Annotation2 ANNOTATION2 = Annotation3.class.getAnnotation(Annotation2.class);
+ private final static Annotation1 ANNOTATION1 = Annotation2.class.getAnnotation(Annotation1.class);
+
+ private final static Annotation4 ANNOTATION4 = Super.class.getAnnotation(Annotation4.class); // Super.class's annotations
+
+ private final static Annotation6 ANNOTATION6 = Interface.class.getAnnotation(Annotation6.class); // Interface.class's annotations
+ private final static Annotation5 ANNOTATION5 = Annotation6.class.getAnnotation(Annotation5.class);
+
+ private final static Annotation[] DECLARED_ANNOTATIONS = new Annotation[]{
+ ANNOTATION3, // Foo.class's annotations
+ ANNOTATION4, // Super.class's annotations
+ ANNOTATION6 // Interface.class's annotations
+ };
+ private final static Annotation[] ANNOTATIONS = new Annotation[]{
+ ANNOTATION3, ANNOTATION2, ANNOTATION1, // Foo.class's annotations
+ ANNOTATION4, // Super.class's annotations
+ ANNOTATION6, ANNOTATION5 // Interface.class's annotations
+ };
+
+ @Test
+ public void testIsAnnotated() {
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation1.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation2.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation3.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation4.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation5.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testFindAnnotation() {
+ Assert.assertEquals(ANNOTATION1, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation1.class));
+ Assert.assertEquals(ANNOTATION2, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation2.class));
+ Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation3.class));
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation4.class));
+ Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation5.class));
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testFindAllAnnotations() {
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION1}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation1.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION2}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation2.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION3}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation3.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION4}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation4.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION5}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation5.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION6}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testFindAnnotations() {
+ Annotation[] annotations = AnnotatedElementUtil.findAnnotations(Foo.class);
+ Assert.assertArrayEquals(ANNOTATIONS, annotations);
+ }
+
+ @Test
+ public void testFindResolvedAnnotation() {
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation4.class));
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation6.class));
+ Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation5.class));
+ }
+
+ @Test
+ public void testFindResolvedAnnotations() {
+ Annotation[] resolvedAnnotations = AnnotatedElementUtil.findResolvedAnnotations(Foo.class);
+ Map, Annotation> annotationMap = Stream.of(resolvedAnnotations).collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
+
+ Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = (Annotation2)annotationMap.get(Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = (Annotation1)annotationMap.get(Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertEquals(ANNOTATION4, annotationMap.get(Annotation4.class));
+ Assert.assertEquals(ANNOTATION6, annotationMap.get(Annotation6.class));
+ Assert.assertEquals(ANNOTATION5, annotationMap.get(Annotation5.class));
+ }
+
+ @Test
+ public void testFindAllResolvedAnnotations() {
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation3.class)[0];
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation2.class)[0];
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation1.class)[0];
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation4.class)[0]);
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation6.class)[0]);
+ Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation5.class)[0]);
+ }
+
+ @Test
+ public void testFindDirectlyAnnotation() {
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation1.class));
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation2.class));
+ Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation3.class));
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation4.class));
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation5.class));
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testFindAllDirectlyAnnotations() {
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation1.class).length);
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation2.class).length);
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION3}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation3.class));
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION4}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation4.class));
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation5.class).length);
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION6}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testFindDirectlyAnnotations() {
+ Assert.assertArrayEquals(
+ DECLARED_ANNOTATIONS, AnnotatedElementUtil.findDirectlyAnnotations(Foo.class)
+ );
+ }
+
+ @Test
+ public void testFindDirectlyResolvedAnnotation() {
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation4.class));
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation6.class));
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation1.class));
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation2.class));
+ Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation5.class));
+ }
+
+ @Test
+ public void testFindDirectlyResolvedAnnotations() {
+ Annotation[] resolvedAnnotations = AnnotatedElementUtil.findDirectlyResolvedAnnotations(Foo.class);
+ Map, Annotation> annotationMap = Stream.of(resolvedAnnotations).collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
+
+ Assert.assertEquals(ANNOTATION4, annotationMap.get(Annotation4.class));
+ Assert.assertEquals(ANNOTATION6, annotationMap.get(Annotation6.class));
+ Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Assert.assertNull(annotationMap.get(Annotation1.class));
+ Assert.assertNull(annotationMap.get(Annotation2.class));
+ Assert.assertNull(annotationMap.get(Annotation5.class));
+ }
+
+ @Test
+ public void testFindAllDirectlyResolvedAnnotations() {
+
+ Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation4.class)[0]);
+ Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation6.class)[0]);
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation3.class)[0];
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation1.class).length);
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation2.class).length);
+ Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation5.class).length);
+ }
+
+ @Test
+ public void testIsAnnotationPresent() {
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation1.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation2.class));
+ Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation3.class));
+
+ Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation4.class));
+ Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation5.class));
+ Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testGetAnnotation() {
+ Assert.assertEquals(ANNOTATION1, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation1.class));
+ Assert.assertEquals(ANNOTATION2, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation2.class));
+ Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation3.class));
+
+ Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation4.class));
+ Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation5.class));
+ Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testGetAnnotations() {
+ Annotation[] annotations = AnnotatedElementUtil.getAnnotations(Foo.class);
+ Assert.assertArrayEquals(
+ new Annotation[]{ ANNOTATION3, ANNOTATION2, ANNOTATION1 },
+ annotations
+ );
+ }
+
+ @Test
+ public void testGetResolvedAnnotation() {
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation4.class));
+ Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation5.class));
+ Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testGetResolvedAnnotations() {
+ Map, Annotation> annotationMap = Stream.of(AnnotatedElementUtil.getResolvedAnnotations(Foo.class))
+ .collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
+
+ Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = (Annotation2)annotationMap.get(Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = (Annotation1)annotationMap.get(Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertFalse(annotationMap.containsKey(Annotation4.class));
+ Assert.assertFalse(annotationMap.containsKey(Annotation5.class));
+ Assert.assertFalse(annotationMap.containsKey(Annotation6.class));
+ }
+
+ @Test
+ public void testGetDirectlyAnnotation() {
+ Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation3.class));
+
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation2.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation1.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation4.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation5.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testGetDirectlyAnnotations() {
+ Annotation[] annotations = AnnotatedElementUtil.getDirectlyAnnotations(Foo.class);
+ Assert.assertEquals(1, annotations.length);
+ Assert.assertEquals(ANNOTATION3, annotations[0]);
+ }
+
+ @Test
+ public void testGetDirectlyResolvedAnnotation() {
+ Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation2.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation1.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation4.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation5.class));
+ Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation6.class));
+ }
+
+ @Test
+ public void testGetDirectlyResolvedAnnotations() {
+ Annotation[] annotations = AnnotatedElementUtil.getDirectlyResolvedAnnotations(Foo.class);
+ Assert.assertEquals(1, annotations.length);
+
+ Annotation3 resolvedAnnotation3 = (Annotation3)annotations[0];
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+ }
+
+ @Test
+ public void testToHierarchyMetaElement() {
+ Assert.assertNotNull(AnnotatedElementUtil.toHierarchyMetaElement(null, false));
+ Assert.assertNotNull(AnnotatedElementUtil.toHierarchyMetaElement(null, true));
+ AnnotatedElement element = AnnotatedElementUtil.toHierarchyMetaElement(Foo.class, false);
+
+ // 带有元注解
+ Assert.assertArrayEquals(ANNOTATIONS, element.getAnnotations());
+
+ // 不带元注解
+ Assert.assertArrayEquals(DECLARED_ANNOTATIONS, element.getDeclaredAnnotations());
+
+ // 解析注解属性
+ AnnotatedElement resolvedElement = AnnotatedElementUtil.toHierarchyMetaElement(Foo.class, true);
+ Annotation3 resolvedAnnotation3 = resolvedElement.getAnnotation(Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = resolvedElement.getAnnotation(Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = resolvedElement.getAnnotation(Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+
+ Assert.assertEquals(ANNOTATION4, resolvedElement.getAnnotation(Annotation4.class));
+ Assert.assertEquals(ANNOTATION6, resolvedElement.getAnnotation(Annotation6.class));
+ Assert.assertEquals(ANNOTATION5, resolvedElement.getAnnotation(Annotation5.class));
+ }
+
+ @Test
+ public void testToHierarchyElement() {
+ Assert.assertNotNull(AnnotatedElementUtil.toHierarchyElement(Foo.class));
+ AnnotatedElement element = AnnotatedElementUtil.toHierarchyElement(Foo.class);
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION3, ANNOTATION4, ANNOTATION6}, element.getAnnotations());
+ }
+
+ @Test
+ public void testToMetaElement() {
+ Assert.assertNotNull(AnnotatedElementUtil.toMetaElement(null, false));
+ Assert.assertNotNull(AnnotatedElementUtil.toMetaElement(null, true));
+
+ // 不解析注解属性
+ AnnotatedElement element = AnnotatedElementUtil.toMetaElement(Foo.class, false);
+ Assert.assertSame(element, AnnotatedElementUtil.toMetaElement(Foo.class, false)); // 第二次获取时从缓存中获取
+ Assert.assertArrayEquals(new Annotation[]{ANNOTATION3, ANNOTATION2, ANNOTATION1}, element.getAnnotations());
+
+ // 解析注解属性
+ element = AnnotatedElementUtil.toMetaElement(Foo.class, true);
+ Assert.assertSame(element, AnnotatedElementUtil.toMetaElement(Foo.class, true)); // 第二次获取时从缓存中获取
+ Assert.assertEquals(3, element.getAnnotations().length);
+
+ Annotation3 resolvedAnnotation3 = element.getAnnotation(Annotation3.class);
+ Assert.assertNotNull(resolvedAnnotation3);
+ Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
+ Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
+
+ Annotation2 resolvedAnnotation2 = element.getAnnotation(Annotation2.class);
+ Assert.assertNotNull(resolvedAnnotation2);
+ Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
+
+ Annotation1 resolvedAnnotation1 = element.getAnnotation(Annotation1.class);
+ Assert.assertNotNull(resolvedAnnotation1);
+ Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
+ Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
+ }
+
+ @Test
+ public void testAsElement() {
+ Annotation[] annotations = new Annotation[]{ANNOTATION1, ANNOTATION2};
+ Assert.assertNotNull(AnnotatedElementUtil.asElement());
+
+ AnnotatedElement element = AnnotatedElementUtil.asElement(ANNOTATION1, null, ANNOTATION2);
+ Assert.assertArrayEquals(annotations, element.getAnnotations());
+ Assert.assertArrayEquals(annotations, element.getDeclaredAnnotations());
+ Assert.assertEquals(ANNOTATION1, element.getAnnotation(Annotation1.class));
+ Assert.assertNull(element.getAnnotation(Annotation3.class));
+ }
+
+ @Test
+ public void testEmptyElement() {
+ AnnotatedElement element = AnnotatedElementUtil.emptyElement();
+ Assert.assertSame(element, AnnotatedElementUtil.emptyElement());
+ Assert.assertNull(element.getAnnotation(Annotation1.class));
+ Assert.assertEquals(0, element.getAnnotations().length);
+ Assert.assertEquals(0, element.getDeclaredAnnotations().length);
+ }
+
+ // ================= super =================
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation4 {}
+
+ @Annotation4
+ private static class Super {};
+
+ // ================= interface =================
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation5 {}
+
+ @Annotation5
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation6 {}
+
+ @Annotation6
+ private interface Interface {};
+
+ // ================= foo =================
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation1 {
+ @Alias("alias")
+ String value() default "";
+ @Alias("value")
+ String alias() default "";
+ }
+
+ @Annotation1
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation2 {
+ int num() default Integer.MIN_VALUE;
+ }
+
+ @Annotation2
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Annotation3 {
+ @Alias("alias")
+ String value() default "";
+ @Alias("value")
+ String alias() default "";
+ int num() default Integer.MIN_VALUE;
+ }
+
+ @Annotation3(value = "foo", num = Integer.MAX_VALUE)
+ private static class Foo extends Super implements Interface {}
+
+}