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