From f118bf8e7e29fca713fb221487081d4075cdda03 Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 27 Apr 2022 11:22:31 +0800 Subject: [PATCH] add predicate for CombinationAnnotationElement --- CHANGELOG.md | 3 +- .../core/annotation/AnnotationUtil.java | 99 ++++++++++++------- .../CombinationAnnotationElement.java | 75 +++++++++++--- .../core/annotation/AnnotationForTest.java | 2 +- .../core/annotation/AnnotationUtilTest.java | 18 +++- .../annotation/RepeatAnnotationForTest.java | 0 6 files changed, 143 insertions(+), 54 deletions(-) mode change 100644 => 100755 hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java mode change 100644 => 100755 hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java mode change 100644 => 100755 hutool-core/src/test/java/cn/hutool/core/annotation/RepeatAnnotationForTest.java 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 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