From ccc9f2568ffdff028e09107e0bbe879b89817b30 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 3 Mar 2022 23:54:47 +0800 Subject: [PATCH] add AnnotationProxy --- CHANGELOG.md | 1 + .../core/annotation/AnnotationProxy.java | 88 +++++++++++++++++++ .../core/annotation/AnnotationUtil.java | 29 +++--- .../java/cn/hutool/core/util/ReflectUtil.java | 3 +- 4 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 940921f73..2cf4af00a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### 🐣新特性 * 【http 】 HttpRequest.form采用TableMap方式(issue#I4W427@gitee) +* 【core 】 AnnotationUtil增加getAnnotationAlias方法(pr#554@gitee) ### 🐞Bug修复 * 【core 】 修复ObjectUtil.hasNull传入null返回true的问题(pr#555@gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java new file mode 100644 index 000000000..a61ff6668 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationProxy.java @@ -0,0 +1,88 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * 注解代理
+ * 通过代理指定注解,可以自定义调用注解的方法逻辑,如支持{@link Alias} 注解 + * + * @param 注解类型 + * @since 5.7.23 + */ +public class AnnotationProxy implements Annotation, InvocationHandler, Serializable { + private static final long serialVersionUID = 1L; + + private final T annotation; + private final Class type; + private final Map attributes; + + /** + * 构造 + * + * @param annotation 注解 + */ + public AnnotationProxy(T annotation) { + this.annotation = annotation; + //noinspection unchecked + this.type = (Class) annotation.annotationType(); + this.attributes = initAttributes(); + } + + + @Override + public Class annotationType() { + return null; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + // 注解别名 + Alias alias = method.getAnnotation(Alias.class); + if(null != alias){ + final String name = alias.value(); + if(StrUtil.isNotBlank(name)){ + if(false == attributes.containsKey(name)){ + throw new IllegalArgumentException(StrUtil.format("No method for alias: [{}]", name)); + } + return attributes.get(name); + } + } + + final Object value = attributes.get(method.getName()); + if (value != null) { + return value; + } + return method.invoke(this, args); + } + + /** + * 初始化注解的属性
+ * 此方法预先调用所有注解的方法,将注解方法值缓存于attributes中 + * + * @return 属性(方法结果)映射 + */ + private Map initAttributes() { + final Method[] methods = ReflectUtil.getMethods(this.type); + final Map attributes = new HashMap<>(methods.length, 1); + + for (Method method : methods) { + // 跳过匿名内部类自动生成的方法 + if (method.isSynthetic()) { + continue; + } + + attributes.put(method.getName(), ReflectUtil.invoke(this.annotation, method)); + } + + return attributes; + } +} 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 index 071cf1b13..be44f080a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -2,11 +2,15 @@ package cn.hutool.core.annotation; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; -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; @@ -38,7 +42,7 @@ public class AnnotationUtil { /** * 获取指定注解 * - * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission * @param isToCombination 是否为转换为组合注解 * @return 注解对象 */ @@ -201,9 +205,9 @@ public class AnnotationUtil { /** * 设置新的注解的属性(字段)值 * - * @param annotation 注解对象 + * @param annotation 注解对象 * @param annotationField 注解属性(字段)名称 - * @param value 要更新的属性值 + * @param value 要更新的属性值 * @since 5.5.2 */ @SuppressWarnings({"rawtypes", "unchecked"}) @@ -219,18 +223,11 @@ public class AnnotationUtil { * @param annotationType 注解类型Class * @param 注解类型 * @return 别名支持后的注解 + * @since 5.7.23 */ @SuppressWarnings("unchecked") public static T getAnnotationAlias(AnnotatedElement annotationEle, Class annotationType) { - T annotation = getAnnotation(annotationEle, annotationType); - Object o = Proxy.newProxyInstance(annotationType.getClassLoader(), new Class[]{annotationType}, (proxy, method, args) -> { - Alias alias = method.getAnnotation(Alias.class); - if (ObjectUtil.isNotNull(alias) && StrUtil.isNotBlank(alias.value())) { - Method aliasMethod = annotationType.getMethod(alias.value()); - return ReflectUtil.invoke(annotation, aliasMethod); - } - return method.invoke(args); - }); - return (T) o; + final T annotation = getAnnotation(annotationEle, annotationType); + return (T) Proxy.newProxyInstance(annotationType.getClassLoader(), new Class[]{annotationType}, new AnnotationProxy<>(annotation)); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java index 43440bb32..de406bfbf 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java @@ -386,7 +386,8 @@ public class ReflectUtil { } /** - * 获得指定类过滤后的Public方法列表 + * 获得指定类过滤后的Public方法列表
+ * TODO 6.x此方法更改返回Method[] * * @param clazz 查找方法的类 * @param filter 过滤器