getAttributeProcessor() {
+ return null;
+ }
+
+ /**
+ * 获取根注解类型
+ *
+ * @return 注解类型
+ */
+ @Override
+ public Class extends Annotation> annotationType() {
+ return this.getClass();
+ }
+
+ /**
+ * 根据指定的属性名与属性类型获取对应的属性值,若存在{@link Alias}则获取{@link Alias#value()}指定的别名属性的值
+ * 当不同层级的注解之间存在同名同类型属性时,将优先获取更接近根注解的属性
+ *
+ * @param attributeName 属性名
+ * @param attributeType 属性类型
+ * @return 属性
+ */
+ @Override
+ public Object getAttribute(String attributeName, Class> attributeType) {
+ return attributeProcessor.getAttributeValue(attributeName, attributeType, metaAnnotationMap.values());
+ }
+
+ /**
+ * 获取被合成的注解
+ *
+ * @param annotationType 注解类型
+ * @param 注解类型
+ * @return 注解对象
+ */
+ @Override
+ public T getAnnotation(Class annotationType) {
+ return Opt.ofNullable(annotationType)
+ .map(metaAnnotationMap::get)
+ .map(MetaAnnotation::getAnnotation)
+ .map(annotationType::cast)
+ .orElse(null);
+ }
+
+ /**
+ * 当前合成注解中是否存在指定元注解
+ *
+ * @param annotationType 注解类型
+ * @return 是否
+ */
+ @Override
+ public boolean isAnnotationPresent(Class extends Annotation> annotationType) {
+ return metaAnnotationMap.containsKey(annotationType);
+ }
+
+ /**
+ * 获取全部注解
+ *
+ * @return 注解对象
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return getMetaAnnotationMap().values().toArray(new MetaAnnotation[0]);
+ }
+
+ /**
+ * 若合成注解在存在指定元注解,则使用动态代理生成一个对应的注解实例
+ *
+ * @param annotationType 注解类型
+ * @return 合成注解对象
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T syntheticAnnotation(Class annotationType) {
+ if (metaAnnotationMap.containsKey(annotationType)) {
+ return (T) Proxy.newProxyInstance(
+ annotationType.getClassLoader(),
+ new Class[]{annotationType, Synthesized.class},
+ new SyntheticAnnotationProxy<>(this, annotationType)
+ );
+ }
+ return null;
+ }
+
+ /**
+ * 获取根注解直接声明的注解,该方法正常情况下当只返回原注解
+ *
+ * @return 直接声明注解
+ */
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return new Annotation[]{getSource()};
+ }
+
+ /**
+ * 广度优先遍历并缓存该根注解上的全部元注解
+ */
+ private void loadMetaAnnotations() {
+ // 若该注解已经是合成注解,则直接使用已解析好的元注解信息
+ if (source instanceof SyntheticMetaAnnotation.Synthesized) {
+ this.metaAnnotationMap.putAll(((Synthesized) source).getMetaAnnotationMap());
+ return;
+ }
+ // 扫描元注解
+ metaAnnotationMap.put(source.annotationType(), new MetaAnnotation(source, source, 0, 0));
+ new MetaAnnotationScanner().scan(
+ (index, annotation) -> {
+ MetaAnnotation oldAnnotation = metaAnnotationMap.get(annotation.annotationType());
+ MetaAnnotation newAnnotation = new MetaAnnotation(source, annotation, index, metaAnnotationMap.size());
+ if (ObjectUtil.isNull(oldAnnotation)) {
+ metaAnnotationMap.put(annotation.annotationType(), newAnnotation);
+ } else {
+ metaAnnotationMap.put(annotation.annotationType(), annotationSelector.choose(oldAnnotation, newAnnotation));
+ }
+ },
+ source.annotationType(), null
+ );
+ }
+
+ /**
+ * 元注解包装类
+ *
+ * @author huangchengxing
+ */
+ public static class MetaAnnotation implements Annotation, SynthesizedAnnotation {
+
+ private final Annotation root;
+ private final Annotation annotation;
+ private final Map attributeMethodCaches;
+ private final int verticalDistance;
+ private final int horizontalDistance;
+
+ public MetaAnnotation(Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) {
+ this.root = root;
+ this.annotation = annotation;
+ this.verticalDistance = verticalDistance;
+ this.horizontalDistance = horizontalDistance;
+ this.attributeMethodCaches = AnnotationUtil.getAttributeMethods(annotation.annotationType());
+ }
+
+ /**
+ * 获取注解类型
+ *
+ * @return 注解类型
+ */
+ @Override
+ public Class extends Annotation> annotationType() {
+ return annotation.annotationType();
+ }
+
+ /**
+ * 获取根注解
+ *
+ * @return 根注解
+ */
+ @Override
+ public Annotation getRoot() {
+ return this.root;
+ }
+
+ /**
+ * 获取元注解
+ *
+ * @return 元注解
+ */
+ @Override
+ public Annotation getAnnotation() {
+ return annotation;
+ }
+
+ /**
+ * 获取根注解到元注解的距离
+ *
+ * @return 根注解到元注解的距离
+ */
+ @Override
+ public int getVerticalDistance() {
+ return verticalDistance;
+ }
+
+ @Override
+ public int getHorizontalDistance() {
+ return horizontalDistance;
+ }
+
+ /**
+ * 元注解是否存在该属性
+ *
+ * @param attributeName 属性名
+ * @return 是否存在该属性
+ */
+ public boolean hasAttribute(String attributeName) {
+ return attributeMethodCaches.containsKey(attributeName);
+ }
+
+ /**
+ * 元注解是否存在该属性,且该属性的值类型是指定类型或其子类
+ *
+ * @param attributeName 属性名
+ * @param returnType 返回值类型
+ * @return 是否存在该属性
+ */
+ @Override
+ public boolean hasAttribute(String attributeName, Class> returnType) {
+ return Opt.ofNullable(attributeMethodCaches.get(attributeName))
+ .filter(method -> ClassUtil.isAssignable(returnType, method.getReturnType()))
+ .isPresent();
+ }
+
+ /**
+ * 获取元注解的属性值
+ *
+ * @param attributeName 属性名
+ * @return 元注解的属性值
+ */
+ @Override
+ public Object getAttribute(String attributeName) {
+ return Opt.ofNullable(attributeMethodCaches.get(attributeName))
+ .map(method -> ReflectUtil.invoke(annotation, method))
+ .orElse(null);
+ }
+
+ }
+
+ /**
+ * 表示一个已经被合成的注解
+ *
+ * @author huangchengxing
+ */
+ interface Synthesized {
+
+ /**
+ * 获取合成注解中已解析的元注解信息
+ *
+ * @return 合成注解中已解析的元注解信息
+ */
+ Map, MetaAnnotation> getMetaAnnotationMap();
+
+ static boolean isMetaAnnotationMapMethod(Method method) {
+ return StrUtil.equals("getMetaAnnotationMap", method.getName());
+ }
+
+ }
+
+ /**
+ * 合成注解代理类
+ *
+ * @author huangchengxing
+ */
+ static class SyntheticAnnotationProxy implements Annotation, InvocationHandler {
+
+ private final Class annotationType;
+ private final SyntheticMetaAnnotation> syntheticMetaAnnotation;
+
+ public SyntheticAnnotationProxy(SyntheticMetaAnnotation> syntheticMetaAnnotation, Class annotationType) {
+ this.syntheticMetaAnnotation = syntheticMetaAnnotation;
+ this.annotationType = annotationType;
+ }
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return annotationType;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (Synthesized.isMetaAnnotationMapMethod(method)) {
+ return syntheticMetaAnnotation.getMetaAnnotationMap();
+ }
+ if (ReflectUtil.isHashCodeMethod(method)) {
+ return getHashCode();
+ }
+ if (ReflectUtil.isToStringMethod(method)) {
+ return getToString();
+ }
+ return ObjectUtil.defaultIfNull(
+ syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType()),
+ () -> ReflectUtil.invoke(this, method, args)
+ );
+ }
+
+ /**
+ * 获取toString值
+ *
+ * @return toString值
+ */
+ private String getToString() {
+ final String attributes = Stream.of(annotationType().getDeclaredMethods())
+ .filter(AnnotationUtil::isAttributeMethod)
+ .map(method -> StrUtil.format("{}={}", method.getName(), syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType())))
+ .collect(Collectors.joining(", "));
+ return StrUtil.format("@{}({})", annotationType().getName(), attributes);
+ }
+
+ /**
+ * 获取hashcode值
+ *
+ * @return hashcode值
+ */
+ private int getHashCode() {
+ return Objects.hash((Object) syntheticMetaAnnotation.getAnnotations());
+ }
+
+ }
+}
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticAnnotationTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticAnnotationTest.java
deleted file mode 100644
index 8e1db5d3f..000000000
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticAnnotationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.hutool.core.annotation;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.lang.annotation.*;
-import java.util.Map;
-
-/**
- * 合成注解{@link SyntheticAnnotation}的测试用例
- *
- * @author huangchengxing
- */
-public class SyntheticAnnotationTest {
-
- @Test
- public void testSynthesisAnnotation() {
- ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
- SyntheticAnnotation syntheticAnnotation = SyntheticAnnotation.of(rootAnnotation);
- Assert.assertEquals(syntheticAnnotation.getSource(), rootAnnotation);
- Assert.assertEquals(syntheticAnnotation.annotationType(), rootAnnotation.annotationType());
- Assert.assertEquals(1, syntheticAnnotation.getDeclaredAnnotations().length);
- Assert.assertEquals(syntheticAnnotation.getDeclaredAnnotations()[0], rootAnnotation);
- Assert.assertEquals(3, syntheticAnnotation.getAnnotations().length);
-
- Assert.assertEquals(syntheticAnnotation.getAttribute("childValue", String.class), "Child!");
- Assert.assertEquals(syntheticAnnotation.getAttribute("childValueAlias", String.class), "Child!");
- Assert.assertEquals(syntheticAnnotation.getAttribute("parentValue", String.class), "Child's Parent!");
- Assert.assertEquals(syntheticAnnotation.getAttribute("grandParentValue", String.class), "Child's GrandParent!");
-
- Map, SyntheticAnnotation.MetaAnnotation> annotationMap = syntheticAnnotation.getMetaAnnotationMap();
- ChildAnnotation childAnnotation = syntheticAnnotation.getAnnotation(ChildAnnotation.class);
- Assert.assertTrue(syntheticAnnotation.isAnnotationPresent(ChildAnnotation.class));
- Assert.assertNotNull(childAnnotation);
- Assert.assertEquals(childAnnotation.childValue(), "Child!");
- Assert.assertEquals(childAnnotation.childValueAlias(), "Child!");
- Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
- Assert.assertEquals(annotationMap, SyntheticAnnotation.of(childAnnotation).getMetaAnnotationMap());
-
- ParentAnnotation parentAnnotation = syntheticAnnotation.getAnnotation(ParentAnnotation.class);
- Assert.assertTrue(syntheticAnnotation.isAnnotationPresent(ParentAnnotation.class));
- Assert.assertNotNull(parentAnnotation);
- Assert.assertEquals(parentAnnotation.parentValue(), "Child's Parent!");
- Assert.assertEquals(parentAnnotation.grandParentType(), "java.lang.Void");
- Assert.assertEquals(annotationMap, SyntheticAnnotation.of(parentAnnotation).getMetaAnnotationMap());
-
- GrandParentAnnotation grandParentAnnotation = syntheticAnnotation.getAnnotation(GrandParentAnnotation.class);
- Assert.assertTrue(syntheticAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
- Assert.assertNotNull(grandParentAnnotation);
- Assert.assertEquals(grandParentAnnotation.grandParentValue(), "Child's GrandParent!");
- Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
- Assert.assertEquals(annotationMap, SyntheticAnnotation.of(grandParentAnnotation).getMetaAnnotationMap());
- }
-
- // 注解结构如下:
- // AnnotatedClass -> @ChildAnnotation -> @ParentAnnotation -> @GrandParentAnnotation
- // -> @GrandParentAnnotation
- @ChildAnnotation(childValueAlias = "Child!", grandParentType = Integer.class)
- static class AnnotatedClass {}
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ ElementType.ANNOTATION_TYPE })
- @interface GrandParentAnnotation {
- String grandParentValue() default "";
- Class> grandParentType() default Void.class;
- }
-
- @GrandParentAnnotation(grandParentValue = "Parent's GrandParent!") // 覆盖元注解@GrandParentAnnotation的属性
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ ElementType.TYPE })
- @interface ParentAnnotation {
- String parentValue() default "";
- String grandParentType() default "java.lang.Void";
- }
-
- @GrandParentAnnotation(grandParentValue = "Child's GrandParent!") // 重复的元注解,靠近根注解的优先级高
- @ParentAnnotation(parentValue = "Child's Parent!") // 覆盖元注解@ParentAnnotation的属性
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ ElementType.METHOD, ElementType.TYPE })
- @interface ChildAnnotation {
- String childValueAlias() default "";
- @Alias("childValueAlias")
- String childValue() default "";
- Class> grandParentType() default Void.class;
- }
-
-}
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java
new file mode 100644
index 000000000..002311593
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java
@@ -0,0 +1,87 @@
+package cn.hutool.core.annotation;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.*;
+import java.util.Map;
+
+/**
+ * 合成注解{@link SyntheticMetaAnnotation}的测试用例
+ *
+ * @author huangchengxing
+ */
+public class SyntheticMetaAnnotationTest {
+
+ @Test
+ public void testSynthesisAnnotation() {
+ ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
+ SyntheticMetaAnnotation syntheticMetaAnnotation = new SyntheticMetaAnnotation<>(rootAnnotation);
+ Assert.assertEquals(syntheticMetaAnnotation.getSource(), rootAnnotation);
+ Assert.assertEquals(syntheticMetaAnnotation.annotationType(), SyntheticMetaAnnotation.class);
+ Assert.assertEquals(1, syntheticMetaAnnotation.getDeclaredAnnotations().length);
+ Assert.assertEquals(syntheticMetaAnnotation.getDeclaredAnnotations()[0], rootAnnotation);
+ Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotations().length);
+
+ Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValue", String.class));
+ Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValueAlias", String.class));
+ Assert.assertEquals("Child's Parent!", syntheticMetaAnnotation.getAttribute("parentValue", String.class));
+ Assert.assertEquals("Child's GrandParent!", syntheticMetaAnnotation.getAttribute("grandParentValue", String.class));
+
+ Map, SyntheticMetaAnnotation.MetaAnnotation> annotationMap = syntheticMetaAnnotation.getMetaAnnotationMap();
+ ChildAnnotation childAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ChildAnnotation.class);
+ Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
+ Assert.assertNotNull(childAnnotation);
+ Assert.assertEquals("Child!", childAnnotation.childValue());
+ Assert.assertEquals("Child!", childAnnotation.childValueAlias());
+ Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
+ Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(childAnnotation).getMetaAnnotationMap());
+
+ ParentAnnotation parentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ParentAnnotation.class);
+ Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
+ Assert.assertNotNull(parentAnnotation);
+ Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
+ Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
+ Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(parentAnnotation).getMetaAnnotationMap());
+
+ GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(GrandParentAnnotation.class);
+ Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
+ Assert.assertNotNull(grandParentAnnotation);
+ Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
+ Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
+ Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(grandParentAnnotation).getMetaAnnotationMap());
+ }
+
+ // 注解结构如下:
+ // AnnotatedClass -> @ChildAnnotation -> @ParentAnnotation -> @GrandParentAnnotation
+ // -> @GrandParentAnnotation
+ @ChildAnnotation(childValueAlias = "Child!", grandParentType = Integer.class)
+ static class AnnotatedClass {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ ElementType.ANNOTATION_TYPE })
+ @interface GrandParentAnnotation {
+ String grandParentValue() default "";
+ Class> grandParentType() default Void.class;
+ }
+
+ @GrandParentAnnotation(grandParentValue = "Parent's GrandParent!") // 覆盖元注解@GrandParentAnnotation的属性
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ ElementType.TYPE })
+ @interface ParentAnnotation {
+ String parentValue() default "";
+ String grandParentType() default "java.lang.Void";
+ }
+
+ @GrandParentAnnotation(grandParentValue = "Child's GrandParent!") // 重复的元注解,靠近根注解的优先级高
+ @ParentAnnotation(parentValue = "Child's Parent!") // 覆盖元注解@ParentAnnotation的属性
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @interface ChildAnnotation {
+ String childValueAlias() default "";
+ @Alias("childValueAlias")
+ String childValue() default "";
+ Class> grandParentType() default Void.class;
+ }
+
+}