diff --git a/CHANGELOG.md b/CHANGELOG.md
index a1afd293c..deb498086 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
-# 5.8.0.M4 (2022-04-25)
+# 5.8.0.M4 (2022-04-27)
### ❌不兼容特性
* 【json 】 【可能兼容问题】JSONArray删除部分构造
@@ -21,6 +21,7 @@
* 【poi 】 ExcelWriter支持重复别名的数据写出(issue#I53APY@Gitee)
* 【core 】 增加Hashids(issue#I53APY@Gitee)
* 【core 】 ReflectUtil.newInstanceIfPossible添加枚举、数组等类型的默认实现
+* 【core 】 CombinationAnnotationElement增加过滤(pr#605@Gitee)
### 🐞Bug修复
* 【core 】 修复StrUtil.firstNonX非static问题(issue#2257@Github)
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java
old mode 100644
new mode 100755
index c84de0073..a75affb8d
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java
@@ -4,14 +4,19 @@ import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
-import java.lang.annotation.*;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
+import java.util.function.Predicate;
/**
* 注解工具类
@@ -39,52 +44,74 @@ public class AnnotationUtil {
* 获取指定注解
*
* @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
- * @param isToCombination 是否为转换为组合注解
+ * @param isToCombination 是否为转换为组合注解,组合注解可以递归获取注解的注解
* @return 注解对象
*/
public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination) {
- return (null == annotationEle) ? null : (isToCombination ? toCombination(annotationEle) : annotationEle).getAnnotations();
+ return getAnnotations(annotationEle, isToCombination, (Predicate) null);
}
/**
- * 获取可重复的注解列表
- * 用于带有同一个注解的多个组合注解
+ * 获取组合注解
*
- * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
- * @param annotationType 注解类型
- * @return 注解列表
- * @param 注解值类型
+ * @param 注解类型
+ * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
+ * @param annotationType 限定的
+ * @return 注解对象数组
+ * @since 5.8.0
*/
- public static Set getRepeatedAnnotations(AnnotatedElement annotationEle, Class annotationType) {
- if (!Annotation.class.isAssignableFrom(annotationType)){
+ public static T[] getCombinationAnnotations(AnnotatedElement annotationEle, Class annotationType) {
+ return getAnnotations(annotationEle, true, annotationType);
+ }
+
+ /**
+ * 获取指定注解
+ *
+ * @param 注解类型
+ * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
+ * @param isToCombination 是否为转换为组合注解,组合注解可以递归获取注解的注解
+ * @param annotationType 限定的
+ * @return 注解对象数组
+ * @since 5.8.0
+ */
+ public static T[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Class annotationType) {
+ final Annotation[] annotations = getAnnotations(annotationEle, isToCombination,
+ (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass())));
+
+ final T[] result = ArrayUtil.newArray(annotationType, annotations.length);
+ for (int i = 0; i < annotations.length; i++) {
+ //noinspection unchecked
+ result[i] = (T) annotations[i];
+ }
+ return result;
+ }
+
+ /**
+ * 获取指定注解
+ *
+ * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
+ * @param isToCombination 是否为转换为组合注解,组合注解可以递归获取注解的注解
+ * @param predicate 过滤器,{@link Predicate#test(Object)}返回{@code true}保留,否则不保留
+ * @return 注解对象
+ * @since 5.8.0
+ */
+ public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate predicate) {
+ if (null == annotationEle) {
return null;
}
- Set annotationList = new HashSet<>();
- recursion(annotationList, annotationEle.getAnnotations(), annotationType);
- return annotationList;
- }
- /**
- * 递归获取注解列表
- *
- * @param list 注解结果集
- * @param annotations 注解参数集
- * @param annotationType 注解类型
- * @param 注解值类型
- */
- private static void recursion(Set list, Annotation[] annotations, Class annotationType) {
- for (Annotation annotation : annotations) {
- Class extends Annotation> clazz = annotation.getClass();
- if (annotationType.isAssignableFrom(clazz)) {
- list.add((T) annotation);
- } else if (!Retention.class.isAssignableFrom(clazz)
- && !Target.class.isAssignableFrom(clazz)
- && !Documented.class.isAssignableFrom(clazz)
- && !Repeatable.class.isAssignableFrom(clazz)
- && !Inherited.class.isAssignableFrom(clazz)) {
- recursion(list, annotation.annotationType().getAnnotations(), annotationType);
+ if (isToCombination) {
+ if (null == predicate) {
+ return toCombination(annotationEle).getAnnotations();
}
+ return CombinationAnnotationElement.of(annotationEle, predicate).getAnnotations();
}
+
+ final Annotation[] result = annotationEle.getAnnotations();
+ if (null == predicate) {
+ return result;
+ }
+ return ArrayUtil.filter(result, predicate::test);
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java
index 90c892be0..542793f79 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java
@@ -1,6 +1,7 @@
package cn.hutool.core.annotation;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.TableMap;
import java.io.Serializable;
import java.lang.annotation.Annotation;
@@ -11,22 +12,36 @@ import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
/**
* 组合注解 对JDK的原生注解机制做一个增强,支持类似Spring的组合注解。
* 核心实现使用了递归获取指定元素上的注解以及注解的注解,以实现复合注解的获取。
*
- * @author Succy,Looly
+ * @author Succy, Looly
* @since 4.0.9
**/
public class CombinationAnnotationElement implements AnnotatedElement, Serializable {
private static final long serialVersionUID = 1L;
- /** 元注解 */
+ /**
+ * 创建CombinationAnnotationElement
+ *
+ * @param element 需要解析注解的元素:可以是Class、Method、Field、Constructor、ReflectPermission
+ * @param predicate 过滤器,{@link Predicate#test(Object)}返回{@code true}保留,否则不保留
+ * @return CombinationAnnotationElement
+ * @since 5.8.0
+ */
+ public static CombinationAnnotationElement of(AnnotatedElement element, Predicate predicate) {
+ return new CombinationAnnotationElement(element, predicate);
+ }
+
+ /**
+ * 元注解
+ */
private static final Set> META_ANNOTATIONS = CollUtil.newHashSet(Target.class, //
Retention.class, //
Inherited.class, //
@@ -36,10 +51,18 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
Deprecated.class//
);
- /** 注解类型与注解对象对应表 */
+ /**
+ * 注解类型与注解对象对应表
+ */
private Map, Annotation> annotationMap;
- /** 直接注解类型与注解对象对应表 */
+ /**
+ * 直接注解类型与注解对象对应表
+ */
private Map, Annotation> declaredAnnotationMap;
+ /**
+ * 过滤器
+ */
+ private final Predicate predicate;
/**
* 构造
@@ -47,6 +70,18 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
* @param element 需要解析注解的元素:可以是Class、Method、Field、Constructor、ReflectPermission
*/
public CombinationAnnotationElement(AnnotatedElement element) {
+ this(element, null);
+ }
+
+ /**
+ * 构造
+ *
+ * @param element 需要解析注解的元素:可以是Class、Method、Field、Constructor、ReflectPermission
+ * @param predicate 过滤器,{@link Predicate#test(Object)}返回{@code true}保留,否则不保留
+ * @since 5.8.0
+ */
+ public CombinationAnnotationElement(AnnotatedElement element, Predicate predicate) {
+ this.predicate = predicate;
init(element);
}
@@ -81,14 +116,14 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
*/
private void init(AnnotatedElement element) {
final Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
- this.declaredAnnotationMap = new HashMap<>();
+ this.declaredAnnotationMap = new TableMap<>();
parseDeclared(declaredAnnotations);
final Annotation[] annotations = element.getAnnotations();
- if(Arrays.equals(declaredAnnotations, annotations)) {
+ if (Arrays.equals(declaredAnnotations, annotations)) {
this.annotationMap = this.declaredAnnotationMap;
- }else {
- this.annotationMap = new HashMap<>();
+ } else {
+ this.annotationMap = new TableMap<>();
parse(annotations);
}
}
@@ -104,7 +139,10 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
for (Annotation annotation : annotations) {
annotationType = annotation.annotationType();
if (false == META_ANNOTATIONS.contains(annotationType)) {
- declaredAnnotationMap.put(annotationType, annotation);
+ if(test(annotation)){
+ declaredAnnotationMap.put(annotationType, annotation);
+ }
+ // 测试不通过的注解,不影响继续递归
parseDeclared(annotationType.getDeclaredAnnotations());
}
}
@@ -120,9 +158,22 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa
for (Annotation annotation : annotations) {
annotationType = annotation.annotationType();
if (false == META_ANNOTATIONS.contains(annotationType)) {
- annotationMap.put(annotationType, annotation);
+ if(test(annotation)){
+ annotationMap.put(annotationType, annotation);
+ }
+ // 测试不通过的注解,不影响继续递归
parse(annotationType.getAnnotations());
}
}
}
-}
\ No newline at end of file
+
+ /**
+ * 检查给定的注解是否符合过滤条件
+ *
+ * @param annotation 注解对象
+ * @return 是否符合条件
+ */
+ private boolean test(Annotation annotation) {
+ return null == this.predicate || this.predicate.test(annotation);
+ }
+}
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationForTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationForTest.java
index 83210ae90..f109e836d 100644
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationForTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationForTest.java
@@ -7,7 +7,7 @@ import java.lang.annotation.Target;
/**
* 用于单元测试的注解类
- * 注解类相关说明见:https://www.cnblogs.com/xdp-gacl/p/3622275.html
+ * 注解类相关说明见:https://www.cnblogs.com/xdp-gacl/p/3622275.html
*
* @author looly
*/
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java
old mode 100644
new mode 100755
index c3077a626..167b62d2c
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java
@@ -3,13 +3,23 @@ package cn.hutool.core.annotation;
import org.junit.Assert;
import org.junit.Test;
-import java.util.Set;
+import java.lang.annotation.Annotation;
public class AnnotationUtilTest {
+
@Test
- public void getRepeatAnnotationValueTest(){
- Set annotations = AnnotationUtil.getRepeatedAnnotations(ClassWithAnnotation.class, AnnotationForTest.class);
- Assert.assertTrue(annotations != null && annotations.size() == 2);
+ public void getCombinationAnnotationsTest(){
+ Annotation[] annotations = AnnotationUtil.getAnnotations(ClassWithAnnotation.class, true);
+ Assert.assertNotNull(annotations);
+ Assert.assertEquals(3, annotations.length);
+ }
+
+ @Test
+ public void getCombinationAnnotationsWithClassTest(){
+ AnnotationForTest[] annotations = AnnotationUtil.getCombinationAnnotations(ClassWithAnnotation.class, AnnotationForTest.class);
+ Assert.assertNotNull(annotations);
+ Assert.assertEquals(2, annotations.length);
+ Assert.assertEquals("测试", annotations[0].value());
}
@Test
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatAnnotationForTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatAnnotationForTest.java
old mode 100644
new mode 100755