假设现有根注解A,A上存在元注解B,B上存在元注解C,则对A解析得到的合成注解X,X作为新的根注解,则CBA都是X的元注解。
+ * 通过{@link #isAnnotationPresent(Class)}可确定指定类型是注解是否是该合成注解的元注解,即是否为当前实例的“父类”。
+ * 若指定注解是当前实例的元注解,则通过{@link #getAnnotation(Class)}可获得动态代理生成的对应的注解实例。
+ * 需要注意的是,由于认为合并注解X以最初的根注解A作为元注解,因此{@link #getAnnotations()}或{@link #getDeclaredAnnotations()}
+ * 都将只能获得A。
+ *
+ *
不同层级的元注解可能存在同名的属性,此时,若认为该合成注解X在第0层,则根注解A在第1层,B在第2层......以此类推。
+ * 层级越低的注解中离根注解距离近,则属性优先级越高,即遵循“就近原则”。
+ * 举个例子:若CBA同时存在属性y,则将X视为C,B或者A时,获得的y属性的值都与最底层元注解A的值保持一致。
+ * 同理,不同层级可能会出现相同的元注解,比如A注解存在元注解B,C,但是C又存在元注解B,因此根据就近原则,A上的元注解B将优先于C上的元注解B生效。
+ * 若两相同注解处于同一层级,则按照从其上一级“子注解”的{@link AnnotatedElement#getAnnotations()}的调用顺序排序。
+ * {@link #getAnnotation(Class)}获得的代理类实例的属性值遵循该规则。
+ *
+ *
别名在合成注解中仍然有效,若注解X中任意属性上存在{@link Alias}注解,则{@link Alias#value()}指定的属性值将会覆盖注解属性的本身的值。 当不同层级的注解之间存在同名属性时,将优先获取更接近根注解的属性
+ *
+ * @param attributeName 属性名
+ */
+ public Object getAttribute(String attributeName) {
+ return attributeCaches.computeIfAbsent(attributeName, a -> metaAnnotationMap.values()
+ .stream()
+ .filter(ma -> ma.hasAttribute(attributeName)) // 集合默认是根据distance有序的,故此处无需再排序
+ .findFirst()
+ .map(ma -> ma.getAttribute(attributeName))
+ .orElse(null)
+ );
+ }
+
+ /**
+ * 若合成注解在存在指定元注解,则使用动态代理生成一个对应的注解实例
+ *
+ * @param annotationType 注解类型
+ * @param 假设现有根注解A,A上存在元注解B,B上存在元注解C,则对A解析得到的合成注解X,X作为新的根注解,则CBA都是X的元注解。 假设现有注解A,A上存在元注解B,B上存在元注解C,则对A解析得到的合成注解X,则CBA都是X的元注解,X为根注解。 同名属性将根据类型彼此隔离,即当不同层级的元注解存在同名的属性,但是属性类型不同时,此时低层级的属性并不会覆盖高层级注解的属性。
+ *
* 别名在合成注解中仍然有效,若注解X中任意属性上存在{@link Alias}注解,则{@link Alias#value()}指定的属性值将会覆盖注解属性的本身的值。 当不同层级的注解之间存在同名属性时,将优先获取更接近根注解的属性
+ * 根据指定的属性名与属性类型获取对应的属性值,若存在{@link Alias}则获取{@link Alias#value()}指定的别名属性的值
+ * 当不同层级的注解之间存在同名同类型属性时,将优先获取更接近根注解的属性
*
* @param attributeName 属性名
*/
- public Object getAttribute(String attributeName) {
- return attributeCaches.computeIfAbsent(attributeName, a -> metaAnnotationMap.values()
+ public Object getAttribute(String attributeName, Class> attributeType) {
+ Map
+ * {@link Alias}注解仅能指定注解X中存在的属性作为别名,不允许指定元注解或子类注解的属性。
+ *
+ * @author huangchengxing
+ * @see AnnotationUtil
+ */
+public class SyntheticAnnotation implements Annotation, AnnotatedElement {
+
+ /**
+ * 根注解,即当前查找的注解
+ */
+ private final A source;
+
+ /**
+ * 包含根注解以及其元注解在内的全部注解实例
+ */
+ private final Map
+ *
+ *
+ * @param annotatedElement 可注解元素
+ * @param annotationType 注解类型
+ * @param
* 方法无参数,且有返回值的方法认为是注解属性的方法。
From 0e2e894a3ec6c3ffa04bc910a329d2fd65f0898d Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Tue, 14 Jun 2022 17:25:57 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E5=90=88=E6=88=90=E6=B3=A8=E8=A7=A3?=
=?UTF-8?q?=E5=B1=9E=E6=80=A7=E8=B0=83=E6=95=B4=E4=B8=BA=E5=90=8C=E6=97=B6?=
=?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=90=8D=E7=A7=B0=E5=92=8C=E7=B1=BB=E5=9E=8B?=
=?UTF-8?q?=E8=BF=9B=E8=A1=8C=E8=A6=86=E7=9B=96;?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/annotation/SyntheticAnnotation.java | 38 ++++++++++++++-----
.../annotation/SyntheticAnnotationTest.java | 18 ++++++---
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
index 2df329754..3db0bacfc 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
@@ -2,6 +2,8 @@ package cn.hutool.core.annotation;
import cn.hutool.core.annotation.scanner.MateAnnotationScanner;
import cn.hutool.core.lang.Opt;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
@@ -21,7 +23,7 @@ import java.util.stream.Stream;
/**
* 表示一个根注解与根注解上的多层元注解合成的注解
*
- *
+ *
* 通过{@link #isAnnotationPresent(Class)}可确定指定类型是注解是否是该合成注解的元注解,即是否为当前实例的“父类”。
* 若指定注解是当前实例的元注解,则通过{@link #getAnnotation(Class)}可获得动态代理生成的对应的注解实例。
* 需要注意的是,由于认为合并注解X以最初的根注解A作为元注解,因此{@link #getAnnotations()}或{@link #getDeclaredAnnotations()}
@@ -34,6 +36,8 @@ import java.util.stream.Stream;
* 若两相同注解处于同一层级,则按照从其上一级“子注解”的{@link AnnotatedElement#getAnnotations()}的调用顺序排序。
* {@link #getAnnotation(Class)}获得的代理类实例的属性值遵循该规则。
*
+ *
* {@link Alias}注解仅能指定注解X中存在的属性作为别名,不允许指定元注解或子类注解的属性。
*
@@ -55,7 +59,7 @@ public class SyntheticAnnotation implements Annotation, An
/**
* 属性值缓存
*/
- private final Map