mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
将合成注解代理类提取为外部类
This commit is contained in:
parent
d20980096e
commit
254e6f5315
@ -6,6 +6,7 @@ import java.lang.reflect.AnnotatedElement;
|
||||
/**
|
||||
* 表示基于特定规则聚合的一组注解
|
||||
*
|
||||
* @param <A> 合成注解类型
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends Annotation, AnnotatedElement {
|
||||
@ -24,6 +25,15 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
|
||||
*/
|
||||
SynthesizedAnnotationAttributeProcessor<A> getAttributeProcessor();
|
||||
|
||||
/**
|
||||
* 获取已合成的注解
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 已合成的注解
|
||||
*/
|
||||
<T extends Annotation> SynthesizedAnnotation<T> getSynthesizedAnnotation(Class<T> annotationType);
|
||||
|
||||
/**
|
||||
* 获取当前的注解类型
|
||||
*
|
||||
@ -38,6 +48,7 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
|
||||
* 获取指定注解对象
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
@Override
|
||||
@ -64,6 +75,7 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
|
||||
* 获取合成注解
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 类型
|
||||
*/
|
||||
<T extends Annotation> T syntheticAnnotation(Class<T> annotationType);
|
||||
@ -80,8 +92,8 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
|
||||
/**
|
||||
* 基于指定根注解,构建包括其元注解在内的合成注解
|
||||
*
|
||||
* @param <T> 注解类型
|
||||
* @param rootAnnotation 根注解
|
||||
* @param <T> 注解类型
|
||||
* @return 合成注解
|
||||
*/
|
||||
static <T extends Annotation> SyntheticAnnotation<SyntheticMetaAnnotation.MetaAnnotation> of(T rootAnnotation) {
|
||||
|
@ -0,0 +1,143 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 合成注解代理类
|
||||
*
|
||||
* @param <A> 代理的注解类型
|
||||
* @author huangchengxing
|
||||
*/
|
||||
class SyntheticAnnotationProxy<A extends Annotation> implements InvocationHandler {
|
||||
|
||||
private final SyntheticAnnotation<?> syntheticAnnotation;
|
||||
private final SynthesizedAnnotation<A> annotation;
|
||||
private final Map<String, BiFunction<Method, Object[], Object>> methods;
|
||||
|
||||
SyntheticAnnotationProxy(SyntheticAnnotation<?> syntheticAnnotation, SynthesizedAnnotation<A> annotation) {
|
||||
this.syntheticAnnotation = syntheticAnnotation;
|
||||
this.annotation = annotation;
|
||||
this.methods = new HashMap<>(9);
|
||||
loadMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个代理注解,生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类。
|
||||
* <ul>
|
||||
* <li>当作为{@code annotationType}所指定的类型使用时,其属性将通过合成它的{@link SyntheticAnnotation}获取;</li>
|
||||
* <li>当作为{@link SyntheticProxyAnnotation}或{@link SynthesizedAnnotation}使用时,将可以获得原始注解实例的相关信息;</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @param syntheticAnnotation 合成注解
|
||||
* @param <A> 代理的注解类型
|
||||
* @return 代理注解
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <A extends Annotation> A create(
|
||||
Class<A> annotationType, SyntheticAnnotation<?> syntheticAnnotation) {
|
||||
final SynthesizedAnnotation<A> annotation = syntheticAnnotation.getSynthesizedAnnotation(annotationType);
|
||||
final SyntheticAnnotationProxy<A> proxyHandler = new SyntheticAnnotationProxy<>(syntheticAnnotation, annotation);
|
||||
if (ObjectUtil.isNull(annotation)) {
|
||||
return null;
|
||||
}
|
||||
return (A) Proxy.newProxyInstance(
|
||||
annotationType.getClassLoader(),
|
||||
new Class[]{annotationType, SyntheticProxyAnnotation.class},
|
||||
proxyHandler
|
||||
);
|
||||
}
|
||||
|
||||
static boolean isProxyAnnotation(Class<?> targetClass) {
|
||||
return ClassUtil.isAssignable(SyntheticProxyAnnotation.class, targetClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
return Opt.ofNullable(methods.get(method.getName()))
|
||||
.map(m -> m.apply(method, args))
|
||||
.orElseGet(() -> ReflectUtil.invoke(this, method, args));
|
||||
}
|
||||
|
||||
// ========================= 代理方法 =========================
|
||||
|
||||
void loadMethods() {
|
||||
methods.put("toString", (method, args) -> proxyToString());
|
||||
methods.put("hashCode", (method, args) -> proxyHashCode());
|
||||
methods.put("getSyntheticAnnotation", (method, args) -> proxyGetSyntheticAnnotation());
|
||||
methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation());
|
||||
methods.put("getRoot", (method, args) -> annotation.getRoot());
|
||||
methods.put("isRoot", (method, args) -> annotation.isRoot());
|
||||
methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance());
|
||||
methods.put("getHorizontalDistance", (method, args) -> annotation.getHorizontalDistance());
|
||||
methods.put("hasAttribute", (method, args) -> annotation.hasAttribute((String)args[0], (Class<?>)args[1]));
|
||||
methods.put("getAttribute", (method, args) -> annotation.getAttribute((String)args[0]));
|
||||
methods.put("annotationType", (method, args) -> annotation.annotationType());
|
||||
for (Method declaredMethod : annotation.getAnnotation().annotationType().getDeclaredMethods()) {
|
||||
methods.put(declaredMethod.getName(), (method, args) -> proxyAttributeValue(method));
|
||||
}
|
||||
}
|
||||
|
||||
private String proxyToString() {
|
||||
final String attributes = Stream.of(annotation.annotationType().getDeclaredMethods())
|
||||
.filter(AnnotationUtil::isAttributeMethod)
|
||||
.map(method -> StrUtil.format("{}={}", method.getName(), syntheticAnnotation.getAttribute(method.getName(), method.getReturnType())))
|
||||
.collect(Collectors.joining(", "));
|
||||
return StrUtil.format("@{}({})", annotation.annotationType().getName(), attributes);
|
||||
}
|
||||
|
||||
private int proxyHashCode() {
|
||||
return Objects.hash(syntheticAnnotation, annotation);
|
||||
}
|
||||
|
||||
private Object proxyGetSyntheticAnnotation() {
|
||||
return syntheticAnnotation;
|
||||
}
|
||||
|
||||
private Object proxyGetSynthesizedAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
private Object proxyAttributeValue(Method attributeMethod) {
|
||||
return syntheticAnnotation.getAttribute(attributeMethod.getName(), attributeMethod.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过代理类生成的合成注解
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
interface SyntheticProxyAnnotation<A extends Annotation, T extends SynthesizedAnnotation<?>> extends SynthesizedAnnotation<A> {
|
||||
|
||||
/**
|
||||
* 获取该注解所属的合成注解
|
||||
*
|
||||
* @return 合成注解
|
||||
*/
|
||||
SyntheticAnnotation<T> getSyntheticAnnotation();
|
||||
|
||||
/**
|
||||
* 获取该代理注解对应的已合成注解
|
||||
*
|
||||
* @return 理注解对应的已合成注解
|
||||
*/
|
||||
SynthesizedAnnotation<A> getSynthesizedAnnotation();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -6,19 +6,13 @@ import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 表示一个根注解与根注解上的多层元注解合成的注解
|
||||
@ -147,6 +141,18 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已合成的注解
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @return 已合成的注解
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends Annotation> SynthesizedAnnotation<T> getSynthesizedAnnotation(Class<T> annotationType) {
|
||||
return (SynthesizedAnnotation<T>)metaAnnotationMap.get(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根注解类型
|
||||
*
|
||||
@ -212,18 +218,11 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @return 合成注解对象
|
||||
* @see SyntheticAnnotationProxy#create(Class, SyntheticAnnotation)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends Annotation> T syntheticAnnotation(Class<T> annotationType) {
|
||||
if (metaAnnotationMap.containsKey(annotationType)) {
|
||||
return (T) Proxy.newProxyInstance(
|
||||
annotationType.getClassLoader(),
|
||||
new Class[]{annotationType, Synthesized.class},
|
||||
new SyntheticAnnotationProxy<>(this, annotationType)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
return SyntheticAnnotationProxy.create(annotationType, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,11 +239,7 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
|
||||
* 广度优先遍历并缓存该根注解上的全部元注解
|
||||
*/
|
||||
private void loadMetaAnnotations() {
|
||||
// 若该注解已经是合成注解,则直接使用已解析好的元注解信息
|
||||
if (source instanceof SyntheticMetaAnnotation.Synthesized) {
|
||||
this.metaAnnotationMap.putAll(((Synthesized) source).getMetaAnnotationMap());
|
||||
return;
|
||||
}
|
||||
Assert.isFalse(SyntheticAnnotationProxy.isProxyAnnotation(source.getClass()), "source [{}] has been synthesized");
|
||||
// 扫描元注解
|
||||
metaAnnotationMap.put(source.annotationType(), new MetaAnnotation(source, source, 0, 0));
|
||||
new MetaAnnotationScanner().scan(
|
||||
@ -366,84 +361,4 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示一个已经被合成的注解
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
interface Synthesized {
|
||||
|
||||
/**
|
||||
* 获取合成注解中已解析的元注解信息
|
||||
*
|
||||
* @return 合成注解中已解析的元注解信息
|
||||
*/
|
||||
Map<Class<? extends Annotation>, MetaAnnotation> getMetaAnnotationMap();
|
||||
|
||||
static boolean isMetaAnnotationMapMethod(Method method) {
|
||||
return StrUtil.equals("getMetaAnnotationMap", method.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 合成注解代理类
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
static class SyntheticAnnotationProxy<A extends Annotation> implements Annotation, InvocationHandler {
|
||||
|
||||
private final Class<A> annotationType;
|
||||
private final SyntheticMetaAnnotation<?> syntheticMetaAnnotation;
|
||||
|
||||
public SyntheticAnnotationProxy(SyntheticMetaAnnotation<?> syntheticMetaAnnotation, Class<A> annotationType) {
|
||||
this.syntheticMetaAnnotation = syntheticMetaAnnotation;
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (Synthesized.isMetaAnnotationMapMethod(method)) {
|
||||
return syntheticMetaAnnotation.getMetaAnnotationMap();
|
||||
}
|
||||
if (ReflectUtil.isHashCodeMethod(method)) {
|
||||
return getHashCode();
|
||||
}
|
||||
if (ReflectUtil.isToStringMethod(method)) {
|
||||
return getToString();
|
||||
}
|
||||
return ObjectUtil.defaultIfNull(
|
||||
syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType()),
|
||||
() -> ReflectUtil.invoke(this, method, args)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取toString值
|
||||
*
|
||||
* @return toString值
|
||||
*/
|
||||
private String getToString() {
|
||||
final String attributes = Stream.of(annotationType().getDeclaredMethods())
|
||||
.filter(AnnotationUtil::isAttributeMethod)
|
||||
.map(method -> StrUtil.format("{}={}", method.getName(), syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType())))
|
||||
.collect(Collectors.joining(", "));
|
||||
return StrUtil.format("@{}({})", annotationType().getName(), attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hashcode值
|
||||
*
|
||||
* @return hashcode值
|
||||
*/
|
||||
private int getHashCode() {
|
||||
return Objects.hash((Object) syntheticMetaAnnotation.getAnnotations());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -35,21 +35,21 @@ public class SyntheticMetaAnnotationTest {
|
||||
Assert.assertEquals("Child!", childAnnotation.childValue());
|
||||
Assert.assertEquals("Child!", childAnnotation.childValueAlias());
|
||||
Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(childAnnotation).getMetaAnnotationMap());
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(childAnnotation));
|
||||
|
||||
ParentAnnotation parentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ParentAnnotation.class);
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
|
||||
Assert.assertNotNull(parentAnnotation);
|
||||
Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
|
||||
Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
|
||||
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(parentAnnotation).getMetaAnnotationMap());
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(parentAnnotation));
|
||||
|
||||
GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(GrandParentAnnotation.class);
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
|
||||
Assert.assertNotNull(grandParentAnnotation);
|
||||
Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
|
||||
Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(grandParentAnnotation).getMetaAnnotationMap());
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(grandParentAnnotation));
|
||||
}
|
||||
|
||||
// 注解结构如下:
|
||||
|
Loading…
x
Reference in New Issue
Block a user