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;
}
}