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] =?UTF-8?q?=E5=90=88=E6=88=90=E6=B3=A8=E8=A7=A3=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E8=B0=83=E6=95=B4=E4=B8=BA=E5=90=8C=E6=97=B6=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E5=90=8D=E7=A7=B0=E5=92=8C=E7=B1=BB=E5=9E=8B=E8=BF=9B?= =?UTF-8?q?=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; /** * 表示一个根注解与根注解上的多层元注解合成的注解 * - *

假设现有根注解A,A上存在元注解B,B上存在元注解C,则对A解析得到的合成注解X,X作为新的根注解,则CBA都是X的元注解。
+ *

假设现有注解A,A上存在元注解B,B上存在元注解C,则对A解析得到的合成注解X,则CBA都是X的元注解,X为根注解。
* 通过{@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)}获得的代理类实例的属性值遵循该规则。 * + *

同名属性将根据类型彼此隔离,即当不同层级的元注解存在同名的属性,但是属性类型不同时,此时低层级的属性并不会覆盖高层级注解的属性。 + * *

别名在合成注解中仍然有效,若注解X中任意属性上存在{@link Alias}注解,则{@link Alias#value()}指定的属性值将会覆盖注解属性的本身的值。
* {@link Alias}注解仅能指定注解X中存在的属性作为别名,不允许指定元注解或子类注解的属性。 * @@ -55,7 +59,7 @@ public class SyntheticAnnotation implements Annotation, An /** * 属性值缓存 */ - private final Map attributeCaches; + private final Map, Object>> attributeCaches; /** * 构造 @@ -108,15 +112,16 @@ public class SyntheticAnnotation implements Annotation, An } /** - * 获取属性值,若存在{@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, Object> values = attributeCaches.computeIfAbsent(attributeName, t -> MapUtil.newHashMap()); + return values.computeIfAbsent(attributeType, a -> metaAnnotationMap.values() .stream() - .filter(ma -> ma.hasAttribute(attributeName)) // 集合默认是根据distance有序的,故此处无需再排序 + .filter(ma -> ma.hasAttribute(attributeName, attributeType)) // 集合默认是根据distance有序的,故此处无需再排序 .findFirst() .map(ma -> ma.getAttribute(attributeName)) .orElse(null) @@ -154,7 +159,7 @@ public class SyntheticAnnotation implements Annotation, An } /** - * 获取根注解直接声明注解 + * 获取根注解直接声明的注解,该方法正常情况下当只返回原注解 * * @return 直接声明注解 */ @@ -238,6 +243,19 @@ public class SyntheticAnnotation implements Annotation, An return attributeMethodCaches.containsKey(attributeName); } + /** + * 元注解是否存在该属性,且该属性的值类型是指定类型或其子类 + * + * @param attributeName 属性名 + * @param returnType 返回值类型 + * @return 是否存在该属性 + */ + public boolean hasAttribute(String attributeName, Class returnType) { + return Opt.ofNullable(attributeMethodCaches.get(attributeName)) + .filter(method -> ClassUtil.isAssignable(returnType, method.getReturnType())) + .isPresent(); + } + /** * 获取元注解的属性值 * @@ -304,7 +322,7 @@ public class SyntheticAnnotation implements Annotation, An return getToString(); } return ObjectUtil.defaultIfNull( - syntheticAnnotation.getAttribute(method.getName()), + syntheticAnnotation.getAttribute(method.getName(), method.getReturnType()), () -> ReflectUtil.invoke(this, method, args) ); } @@ -317,7 +335,7 @@ public class SyntheticAnnotation implements Annotation, An private String getToString() { String attributes = Stream.of(annotationType().getDeclaredMethods()) .filter(AnnotationUtil::isAttributeMethod) - .map(method -> StrUtil.format("{}={}", method.getName(), syntheticAnnotation.getAttribute(method.getName()))) + .map(method -> StrUtil.format("{}={}", method.getName(), syntheticAnnotation.getAttribute(method.getName(), method.getReturnType()))) .collect(Collectors.joining(", ")); return StrUtil.format("@{}({})", annotationType().getName(), attributes); } 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 index a81147e2e..8e1db5d3f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticAnnotationTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticAnnotationTest.java @@ -23,10 +23,10 @@ public class SyntheticAnnotationTest { Assert.assertEquals(syntheticAnnotation.getDeclaredAnnotations()[0], rootAnnotation); Assert.assertEquals(3, syntheticAnnotation.getAnnotations().length); - Assert.assertEquals(syntheticAnnotation.getAttribute("childValue"), "Child!"); - Assert.assertEquals(syntheticAnnotation.getAttribute("childValueAlias"), "Child!"); - Assert.assertEquals(syntheticAnnotation.getAttribute("parentValue"), "Child's Parent!"); - Assert.assertEquals(syntheticAnnotation.getAttribute("grandParentValue"), "Child's GrandParent!"); + 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); @@ -34,31 +34,35 @@ public class SyntheticAnnotationTest { 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!") - class AnnotatedClass {} + @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的属性 @@ -66,6 +70,7 @@ public class SyntheticAnnotationTest { @Target({ ElementType.TYPE }) @interface ParentAnnotation { String parentValue() default ""; + String grandParentType() default "java.lang.Void"; } @GrandParentAnnotation(grandParentValue = "Child's GrandParent!") // 重复的元注解,靠近根注解的优先级高 @@ -76,6 +81,7 @@ public class SyntheticAnnotationTest { String childValueAlias() default ""; @Alias("childValueAlias") String childValue() default ""; + Class grandParentType() default Void.class; } }