调整方法、变量与类名,完善测试用例

This commit is contained in:
huangchengxing 2022-07-13 22:36:08 +08:00
parent eae76eb275
commit 18c7a78062
29 changed files with 945 additions and 241 deletions

View File

@ -8,19 +8,19 @@ import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
* {@link AnnotationAttributeWrapper}的基本实现 * {@link WrappedAnnotationAttribute}的基本实现
* *
* @author huangchengxing * @author huangchengxing
* @see ForceAliasedAnnotationAttribute * @see ForceAliasedAnnotationAttribute
* @see AliasedAnnotationAttribute * @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute * @see MirroredAnnotationAttribute
*/ */
public abstract class AbstractAnnotationAttributeWrapper implements AnnotationAttributeWrapper { public abstract class AbstractWrappedAnnotationAttribute implements WrappedAnnotationAttribute {
protected final AnnotationAttribute original; protected final AnnotationAttribute original;
protected final AnnotationAttribute linked; protected final AnnotationAttribute linked;
protected AbstractAnnotationAttributeWrapper(AnnotationAttribute original, AnnotationAttribute linked) { protected AbstractWrappedAnnotationAttribute(AnnotationAttribute original, AnnotationAttribute linked) {
Assert.notNull(original, "target must not null"); Assert.notNull(original, "target must not null");
Assert.notNull(linked, "linked must not null"); Assert.notNull(linked, "linked must not null");
this.original = original; this.original = original;
@ -43,7 +43,7 @@ public abstract class AbstractAnnotationAttributeWrapper implements AnnotationAt
AnnotationAttribute next = original; AnnotationAttribute next = original;
while (next != null) { while (next != null) {
curr = next; curr = next;
next = next.isWrapped() ? ((AnnotationAttributeWrapper)curr).getOriginal() : null; next = next.isWrapped() ? ((WrappedAnnotationAttribute)curr).getOriginal() : null;
} }
return curr; return curr;
} }
@ -63,7 +63,7 @@ public abstract class AbstractAnnotationAttributeWrapper implements AnnotationAt
leafAttributes.add(curr); leafAttributes.add(curr);
return; return;
} }
AnnotationAttributeWrapper wrappedAttribute = (AnnotationAttributeWrapper)curr; WrappedAnnotationAttribute wrappedAttribute = (WrappedAnnotationAttribute)curr;
collectLeafAttribute(wrappedAttribute.getOriginal(), leafAttributes); collectLeafAttribute(wrappedAttribute.getOriginal(), leafAttributes);
collectLeafAttribute(wrappedAttribute.getLinked(), leafAttributes); collectLeafAttribute(wrappedAttribute.getLinked(), leafAttributes);
} }

View File

@ -25,7 +25,7 @@ public class AliasAttributePostProcessor implements SynthesizedAnnotationPostPro
} }
@Override @Override
public void process(SynthesizedAnnotation annotation, SyntheticAnnotation syntheticAnnotation) { public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) {
final Map<String, AnnotationAttribute> attributeMap = annotation.getAttributes(); final Map<String, AnnotationAttribute> attributeMap = annotation.getAttributes();
// 记录别名与属性的关系 // 记录别名与属性的关系
@ -47,7 +47,6 @@ public class AliasAttributePostProcessor implements SynthesizedAnnotationPostPro
final AnnotationAttribute resolvedAttribute = Opt.ofNullable(attributeName) final AnnotationAttribute resolvedAttribute = Opt.ofNullable(attributeName)
.map(attributeAliasMappings::getRootNode) .map(attributeAliasMappings::getRootNode)
.map(TreeEntry::getValue) .map(TreeEntry::getValue)
.map(aliasAttribute -> (AnnotationAttribute)new ForceAliasedAnnotationAttribute(attribute, aliasAttribute))
.orElse(attribute); .orElse(attribute);
Assert.isTrue( Assert.isTrue(
ObjectUtil.isNull(resolvedAttribute) ObjectUtil.isNull(resolvedAttribute)
@ -55,7 +54,9 @@ public class AliasAttributePostProcessor implements SynthesizedAnnotationPostPro
"return type of the root alias method [{}] is inconsistent with the original [{}]", "return type of the root alias method [{}] is inconsistent with the original [{}]",
resolvedAttribute.getClass(), attribute.getAttributeType() resolvedAttribute.getClass(), attribute.getAttributeType()
); );
attributeMap.put(attributeName, resolvedAttribute); if (attribute != resolvedAttribute) {
attributeMap.put(attributeName, new ForceAliasedAnnotationAttribute(attribute, resolvedAttribute));
}
}); });
annotation.setAttributes(attributeMap); annotation.setAttributes(attributeMap);
} }

View File

@ -24,7 +24,7 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
} }
@Override @Override
public void process(SynthesizedAnnotation annotation, SyntheticAnnotation syntheticAnnotation) { public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) {
final Map<String, AnnotationAttribute> attributeMap = new HashMap<>(annotation.getAttributes()); final Map<String, AnnotationAttribute> attributeMap = new HashMap<>(annotation.getAttributes());
attributeMap.forEach((originalAttributeName, originalAttribute) -> { attributeMap.forEach((originalAttributeName, originalAttribute) -> {
// 获取注解 // 获取注解
@ -36,7 +36,7 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
} }
// 获取注解属性 // 获取注解属性
final SynthesizedAnnotation aliasAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, syntheticAnnotation, annotation.annotationType()); final SynthesizedAnnotation aliasAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, synthesizedAnnotationAggregator, annotation.annotationType());
if (ObjectUtil.isNull(aliasAnnotation)) { if (ObjectUtil.isNull(aliasAnnotation)) {
return; return;
} }
@ -47,11 +47,11 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
// aliasFor // aliasFor
if (RelationType.ALIAS_FOR.equals(link.type())) { if (RelationType.ALIAS_FOR.equals(link.type())) {
wrappingLinkedAttribute(syntheticAnnotation, originalAttribute, aliasAttribute, AliasedAnnotationAttribute::new); wrappingLinkedAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, AliasedAnnotationAttribute::new);
return; return;
} }
// forceAliasFor // forceAliasFor
wrappingLinkedAttribute(syntheticAnnotation, originalAttribute, aliasAttribute, ForceAliasedAnnotationAttribute::new); wrappingLinkedAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, ForceAliasedAnnotationAttribute::new);
}); });
} }
@ -59,16 +59,16 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
* 对指定注解属性进行包装若该属性已被包装过则递归以其为根节点的树结构对树上全部的叶子节点进行包装 * 对指定注解属性进行包装若该属性已被包装过则递归以其为根节点的树结构对树上全部的叶子节点进行包装
*/ */
private void wrappingLinkedAttribute( private void wrappingLinkedAttribute(
SyntheticAnnotation syntheticAnnotation, AnnotationAttribute originalAttribute, AnnotationAttribute aliasAttribute, BinaryOperator<AnnotationAttribute> wrapping) { SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute, AnnotationAttribute aliasAttribute, BinaryOperator<AnnotationAttribute> wrapping) {
// 不是包装属性 // 不是包装属性
if (!aliasAttribute.isWrapped()) { if (!aliasAttribute.isWrapped()) {
processAttribute(syntheticAnnotation, originalAttribute, aliasAttribute, wrapping); processAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, wrapping);
return; return;
} }
// 是包装属性 // 是包装属性
final AbstractAnnotationAttributeWrapper wrapper = (AbstractAnnotationAttributeWrapper)aliasAttribute; final AbstractWrappedAnnotationAttribute wrapper = (AbstractWrappedAnnotationAttribute)aliasAttribute;
wrapper.getAllLinkedNonWrappedAttributes().forEach( wrapper.getAllLinkedNonWrappedAttributes().forEach(
t -> processAttribute(syntheticAnnotation, originalAttribute, t, wrapping) t -> processAttribute(synthesizedAnnotationAggregator, originalAttribute, t, wrapping)
); );
} }
@ -76,10 +76,10 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
* 获取指定注解属性然后将其再进行一层包装 * 获取指定注解属性然后将其再进行一层包装
*/ */
private void processAttribute( private void processAttribute(
SyntheticAnnotation syntheticAnnotation, AnnotationAttribute originalAttribute, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute,
AnnotationAttribute target, BinaryOperator<AnnotationAttribute> wrapping) { AnnotationAttribute target, BinaryOperator<AnnotationAttribute> wrapping) {
Opt.ofNullable(target.getAnnotationType()) Opt.ofNullable(target.getAnnotationType())
.map(syntheticAnnotation::getSynthesizedAnnotation) .map(synthesizedAnnotationAggregator::getSynthesizedAnnotation)
.ifPresent(t -> t.replaceAttribute(target.getAttributeName(), old -> wrapping.apply(old, originalAttribute))); .ifPresent(t -> t.replaceAttribute(target.getAttributeName(), old -> wrapping.apply(old, originalAttribute)));
} }
@ -87,6 +87,7 @@ public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotation
* 检查两个属性是否互为别名 * 检查两个属性是否互为别名
*/ */
private void checkCircularDependency(AnnotationAttribute original, AnnotationAttribute alias) { private void checkCircularDependency(AnnotationAttribute original, AnnotationAttribute alias) {
SyntheticAnnotationUtil.checkLinkedSelf(original, alias);
Link annotation = SyntheticAnnotationUtil.getLink(alias, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR); Link annotation = SyntheticAnnotationUtil.getLink(alias, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR);
if (ObjectUtil.isNull(annotation)) { if (ObjectUtil.isNull(annotation)) {
return; return;

View File

@ -9,7 +9,7 @@ package cn.hutool.core.annotation;
* @see RelationType#FORCE_ALIAS_FOR * @see RelationType#FORCE_ALIAS_FOR
* @see RelationType#ALIAS_FOR * @see RelationType#ALIAS_FOR
*/ */
public class AliasedAnnotationAttribute extends AbstractAnnotationAttributeWrapper { public class AliasedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
protected AliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) { protected AliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked); super(origin, linked);

View File

@ -0,0 +1,49 @@
package cn.hutool.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
/**
* 表示一组被聚合在一起的注解对象
*
* @author huangchengxing
*/
public interface AnnotationAggregator extends AnnotatedElement {
/**
* 获取在聚合中存在的指定注解对象
*
* @param annotationType 注解类型
* @param <T> 注解类型
* @return 注解对象
*/
@Override
<T extends Annotation> T getAnnotation(Class<T> annotationType);
/**
* 在聚合中是否存在的指定类型注解对象
*
* @param annotationType 注解类型
* @return 是否
*/
@Override
boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/**
* 获取聚合中的全部注解对象
*
* @return 注解对象
*/
@Override
Annotation[] getAnnotations();
/**
* 从聚合中获取指定类型的属性值
*
* @param attributeName 属性名称
* @param attributeType 属性类型
* @return 属性值
*/
Object getAttribute(String attributeName, Class<?> attributeType);
}

View File

@ -1,6 +1,5 @@
package cn.hutool.core.annotation; package cn.hutool.core.annotation;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -8,7 +7,7 @@ import java.lang.reflect.Method;
/** /**
* <p>表示注解的某个属性等同于绑定的调用对象的{@link Method}方法<br> * <p>表示注解的某个属性等同于绑定的调用对象的{@link Method}方法<br>
* {@link SyntheticAnnotation}的解析以及取值过程中 * {@link SynthesizedAnnotationAggregator}的解析以及取值过程中
* 可以通过设置{@link SynthesizedAnnotation}的注解属性 * 可以通过设置{@link SynthesizedAnnotation}的注解属性
* 从而使得可以从一个注解对象中属性获取另一个注解对象的属性值 * 从而使得可以从一个注解对象中属性获取另一个注解对象的属性值
* *
@ -16,9 +15,9 @@ import java.lang.reflect.Method;
* *
* @author huangchengxing * @author huangchengxing
* @see SynthesizedAnnotationPostProcessor * @see SynthesizedAnnotationPostProcessor
* @see AnnotationAttributeWrapper * @see WrappedAnnotationAttribute
* @see CacheableAnnotationAttribute * @see CacheableAnnotationAttribute
* @see AbstractAnnotationAttributeWrapper * @see AbstractWrappedAnnotationAttribute
* @see ForceAliasedAnnotationAttribute * @see ForceAliasedAnnotationAttribute
* @see AliasedAnnotationAttribute * @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute * @see MirroredAnnotationAttribute
@ -71,9 +70,7 @@ public interface AnnotationAttribute {
* *
* @return 该注解属性的值是否等于默认值 * @return 该注解属性的值是否等于默认值
*/ */
default boolean isValueEquivalentToDefaultValue() { boolean isValueEquivalentToDefaultValue();
return ObjectUtil.equals(getValue(), getAttribute().getDefaultValue());
}
/** /**
* 获取属性类型 * 获取属性类型
@ -95,7 +92,7 @@ public interface AnnotationAttribute {
} }
/** /**
* 当前注解属性是否已经被{@link AnnotationAttributeWrapper}包装 * 当前注解属性是否已经被{@link WrappedAnnotationAttribute}包装
* *
* @return boolean * @return boolean
*/ */

View File

@ -3,10 +3,7 @@ package cn.hutool.core.annotation;
import cn.hutool.core.annotation.scanner.*; import cn.hutool.core.annotation.scanner.*;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
@ -15,10 +12,8 @@ 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.*; import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* 注解工具类<br> * 注解工具类<br>
@ -356,11 +351,11 @@ public class AnnotationUtil {
* @param annotationType 注解类 * @param annotationType 注解类
* @param <T> 注解类型 * @param <T> 注解类型
* @return 合成注解 * @return 合成注解
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
*/ */
public static <T extends Annotation> T getSynthesisAnnotation(Annotation annotation, Class<T> annotationType) { public static <T extends Annotation> T getSynthesisAnnotation(Annotation annotation, Class<T> annotationType) {
// TODO 缓存合成注解信息避免重复解析 // TODO 缓存合成注解信息避免重复解析
return SyntheticAnnotation.of(annotation).syntheticAnnotation(annotationType); return SynthesizedAnnotationAggregator.of(annotation).synthesize(annotationType);
} }
/** /**
@ -374,7 +369,7 @@ public class AnnotationUtil {
* @param annotationType 注解类 * @param annotationType 注解类
* @param <T> 注解类型 * @param <T> 注解类型
* @return 合成注解 * @return 合成注解
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
*/ */
public static <T extends Annotation> List<T> getAllSynthesisAnnotations(AnnotatedElement annotatedEle, Class<T> annotationType) { public static <T extends Annotation> List<T> getAllSynthesisAnnotations(AnnotatedElement annotatedEle, Class<T> annotationType) {
AnnotationScanner[] scanners = new AnnotationScanner[]{ AnnotationScanner[] scanners = new AnnotationScanner[]{
@ -397,9 +392,13 @@ public class AnnotationUtil {
* @param annotationType 注解类 * @param annotationType 注解类
* @param <T> 注解类型 * @param <T> 注解类型
* @return 合成注解 * @return 合成注解
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
*/ */
public static <T extends Annotation> T getSyntheticAnnotation(AnnotatedElement annotatedEle, Class<T> annotationType) { public static <T extends Annotation> T getSyntheticAnnotation(AnnotatedElement annotatedEle, Class<T> annotationType) {
T target = annotatedEle.getAnnotation(annotationType);
if (ObjectUtil.isNotNull(target)) {
return target;
}
AnnotationScanner[] scanners = new AnnotationScanner[]{ AnnotationScanner[] scanners = new AnnotationScanner[]{
new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner() new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner()
}; };
@ -471,36 +470,4 @@ public class AnnotationUtil {
return method.getParameterCount() == 0 && method.getReturnType() != void.class; return method.getParameterCount() == 0 && method.getReturnType() != void.class;
} }
/**
* 获取注解的全部属性值获取方法
*
* @param annotationType 注解
* @return 注解的全部属性值
* @throws IllegalArgumentException 当别名属性在注解中不存在或别名属性的值与原属性的值类型不一致时抛出
*/
static Map<String, Method> getAttributeMethods(Class<? extends Annotation> annotationType) {
// 获取全部注解属性值
Map<String, Method> attributeMethods = Stream.of(annotationType.getDeclaredMethods())
.filter(AnnotationUtil::isAttributeMethod)
.collect(Collectors.toMap(Method::getName, Function.identity()));
// 处理别名
attributeMethods.forEach((methodName, method) -> {
String alias = Opt.ofNullable(method.getAnnotation(Alias.class))
.map(Alias::value)
.orElse(null);
if (ObjectUtil.isNull(alias)) {
return;
}
// 存在别名则将原本的值替换为别名对应的值
Assert.isTrue(attributeMethods.containsKey(alias), "No method for alias: [{}]", alias);
Method aliasAttributeMethod = attributeMethods.get(alias);
Assert.isTrue(
ObjectUtil.isNull(aliasAttributeMethod) || ClassUtil.isAssignable(method.getReturnType(), aliasAttributeMethod.getReturnType()),
"Return type of the alias method [{}] is inconsistent with the original [{}]",
aliasAttributeMethod.getClass(), method.getParameterTypes()
);
attributeMethods.put(methodName, aliasAttributeMethod);
});
return attributeMethods;
}
} }

View File

@ -10,7 +10,7 @@ package cn.hutool.core.annotation;
* @see RelationType#ALIAS_FOR * @see RelationType#ALIAS_FOR
* @see RelationType#FORCE_ALIAS_FOR * @see RelationType#FORCE_ALIAS_FOR
*/ */
public class ForceAliasedAnnotationAttribute extends AbstractAnnotationAttributeWrapper { public class ForceAliasedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
protected ForceAliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) { protected ForceAliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked); super(origin, linked);

View File

@ -4,7 +4,7 @@ import java.lang.annotation.*;
/** /**
* <p>用于在同一注解中或具有一定关联的不同注解的属性中表明这些属性之间具有特定的关联关系 * <p>用于在同一注解中或具有一定关联的不同注解的属性中表明这些属性之间具有特定的关联关系
* 在通过{@link SyntheticAnnotation}获取合成注解后合成注解获取属性值时会根据该注解进行调整<br /> * 在通过{@link SynthesizedAnnotationAggregator}获取合成注解后合成注解获取属性值时会根据该注解进行调整<br />
* *
* <p>该注解存在三个字注解{@link MirrorFor}{@link ForceAliasFor}{@link AliasFor} * <p>该注解存在三个字注解{@link MirrorFor}{@link ForceAliasFor}{@link AliasFor}
* 使用三个子注解等同于{@link Link}但是需要注意的是 * 使用三个子注解等同于{@link Link}但是需要注意的是
@ -14,7 +14,7 @@ import java.lang.annotation.*;
* <b>注意该注解的优先级低于{@link Alias}</b> * <b>注意该注解的优先级低于{@link Alias}</b>
* *
* @author huangchengxing * @author huangchengxing
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
* @see RelationType * @see RelationType
* @see AliasFor * @see AliasFor
* @see MirrorFor * @see MirrorFor

View File

@ -20,7 +20,7 @@ public class MirrorLinkAttributePostProcessor implements SynthesizedAnnotationPo
} }
@Override @Override
public void process(SynthesizedAnnotation annotation, SyntheticAnnotation syntheticAnnotation) { public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) {
Map<String, AnnotationAttribute> attributeMap = new HashMap<>(annotation.getAttributes()); Map<String, AnnotationAttribute> attributeMap = new HashMap<>(annotation.getAttributes());
attributeMap.forEach((originalAttributeName, originalAttribute) -> { attributeMap.forEach((originalAttributeName, originalAttribute) -> {
// 跳过已经解析的镜像属性 // 跳过已经解析的镜像属性
@ -35,7 +35,7 @@ public class MirrorLinkAttributePostProcessor implements SynthesizedAnnotationPo
} }
// 获取指定镜像属性所在的注解 // 获取指定镜像属性所在的注解
final SynthesizedAnnotation mirrorAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, syntheticAnnotation, annotation.annotationType()); final SynthesizedAnnotation mirrorAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, synthesizedAnnotationAggregator, annotation.annotationType());
if (ObjectUtil.isNull(mirrorAnnotation)) { if (ObjectUtil.isNull(mirrorAnnotation)) {
return; return;
} }
@ -46,7 +46,7 @@ public class MirrorLinkAttributePostProcessor implements SynthesizedAnnotationPo
// 包装这一对镜像属性并替换原注解中的对应属性 // 包装这一对镜像属性并替换原注解中的对应属性
final AnnotationAttribute mirroredOriginalAttribute = new MirroredAnnotationAttribute(originalAttribute, mirrorAttribute); final AnnotationAttribute mirroredOriginalAttribute = new MirroredAnnotationAttribute(originalAttribute, mirrorAttribute);
syntheticAnnotation.getSynthesizedAnnotation(originalAttribute.getAnnotationType()) synthesizedAnnotationAggregator.getSynthesizedAnnotation(originalAttribute.getAnnotationType())
.setAttribute(originalAttributeName, mirroredOriginalAttribute); .setAttribute(originalAttributeName, mirroredOriginalAttribute);
final AnnotationAttribute mirroredTargetAttribute = new MirroredAnnotationAttribute(mirrorAttribute, originalAttribute); final AnnotationAttribute mirroredTargetAttribute = new MirroredAnnotationAttribute(mirrorAttribute, originalAttribute);
mirrorAnnotation.setAttribute(link.attribute(), mirroredTargetAttribute); mirrorAnnotation.setAttribute(link.attribute(), mirroredTargetAttribute);
@ -65,6 +65,7 @@ public class MirrorLinkAttributePostProcessor implements SynthesizedAnnotationPo
"mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]", "mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]",
mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR
); );
SyntheticAnnotationUtil.checkLinkedSelf(original, mirror);
} }
} }

View File

@ -9,7 +9,7 @@ import cn.hutool.core.lang.Assert;
* @see MirrorLinkAttributePostProcessor * @see MirrorLinkAttributePostProcessor
* @see RelationType#MIRROR_FOR * @see RelationType#MIRROR_FOR
*/ */
public class MirroredAnnotationAttribute extends AbstractAnnotationAttributeWrapper { public class MirroredAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
public MirroredAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) { public MirroredAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked); super(origin, linked);

View File

@ -3,8 +3,8 @@ package cn.hutool.core.annotation;
/** /**
* <p>注解属性的关系类型 <br> * <p>注解属性的关系类型 <br>
* 若将被{@link Link}注解的属性称为原始属性而在{@link Link}注解中指向的注解属性称为关联属性 * 若将被{@link Link}注解的属性称为原始属性而在{@link Link}注解中指向的注解属性称为关联属性
* 则该枚举用于描述原始属性关联属性{@link SyntheticAnnotation}处理过程中的作用关系<br> * 则该枚举用于描述原始属性关联属性{@link SynthesizedAnnotationAggregator}处理过程中的作用关系<br>
* 根据在{@link Link#type()}中指定的关系类型的不同通过{@link SyntheticAnnotation}合成的注解的属性值也将有所变化 * 根据在{@link Link#type()}中指定的关系类型的不同通过{@link SynthesizedAnnotationAggregator}合成的注解的属性值也将有所变化
* *
* <p>当一个注解中的所有属性同时具备多种关系时将依次按下述顺序处理 * <p>当一个注解中的所有属性同时具备多种关系时将依次按下述顺序处理
* <ol> * <ol>
@ -15,7 +15,7 @@ package cn.hutool.core.annotation;
* </ol> * </ol>
* *
* @author huangchengxing * @author huangchengxing
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
* @see Link * @see Link
*/ */
public enum RelationType { public enum RelationType {

View File

@ -7,14 +7,14 @@ import java.util.Map;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
/** /**
* <p>用于在{@link SyntheticAnnotation}中表示一个处于合成状态的注解对象<br> * <p>用于在{@link SynthesizedAnnotationAggregator}中表示一个处于合成状态的注解对象<br>
* 当对多个合成注解排序时默认先按{@link #getVerticalDistance()}排序 * 当对多个合成注解排序时默认先按{@link #getVerticalDistance()}排序
* 再按{@link #getHorizontalDistance()}排序 * 再按{@link #getHorizontalDistance()}排序
* 该顺序应当保证当合成注解与其他注解存在层级关系时 * 该顺序应当保证当合成注解与其他注解存在层级关系时
* 离根对象最接近的注解被排在靠前的位置 * 离根对象最接近的注解被排在靠前的位置
* *
* @author huangchengxing * @author huangchengxing
* @see SyntheticAnnotation * @see SynthesizedAnnotationAggregator
*/ */
public interface SynthesizedAnnotation extends Annotation, Comparable<SynthesizedAnnotation> { public interface SynthesizedAnnotation extends Annotation, Comparable<SynthesizedAnnotation> {
@ -23,7 +23,7 @@ public interface SynthesizedAnnotation extends Annotation, Comparable<Synthesize
* *
* @return 合成注解 * @return 合成注解
*/ */
SyntheticAnnotation getOwner(); SynthesizedAnnotationAggregator getOwner();
/** /**
* 获取该合成注解对应的根节点 * 获取该合成注解对应的根节点
@ -32,15 +32,6 @@ public interface SynthesizedAnnotation extends Annotation, Comparable<Synthesize
*/ */
Object getRoot(); Object getRoot();
/**
* 该合成注解是为根对象
*
* @return 根对象
*/
default boolean isRoot() {
return getRoot() == this;
}
/** /**
* 获取被合成的注解对象 * 获取被合成的注解对象
* *

View File

@ -10,7 +10,7 @@ import java.util.Collection;
* <p>合成注解一般被用于处理类层级结果中具有直接或间接关联的注解对象 * <p>合成注解一般被用于处理类层级结果中具有直接或间接关联的注解对象
* 当实例被创建时会获取到这些注解对象并使用{@link SynthesizedAnnotationSelector}对类型相同的注解进行过滤 * 当实例被创建时会获取到这些注解对象并使用{@link SynthesizedAnnotationSelector}对类型相同的注解进行过滤
* 并最终得到类型不重复的有效注解对象这些有效注解将被包装为{@link SynthesizedAnnotation} * 并最终得到类型不重复的有效注解对象这些有效注解将被包装为{@link SynthesizedAnnotation}
* 然后最终用于合成一个{@link SyntheticAnnotation}<br> * 然后最终用于合成一个{@link SynthesizedAnnotationAggregator}<br>
* {@link SynthesizedAnnotationSelector}是合成注解生命周期中的第一个钩子 * {@link SynthesizedAnnotationSelector}是合成注解生命周期中的第一个钩子
* 自定义选择器以拦截原始注解被扫描的过程 * 自定义选择器以拦截原始注解被扫描的过程
* *
@ -21,7 +21,7 @@ import java.util.Collection;
* {@link SynthesizedAnnotationPostProcessor}是合成注解生命周期中的第二个钩子 * {@link SynthesizedAnnotationPostProcessor}是合成注解生命周期中的第二个钩子
* 自定义后置处理器以拦截原始在转为待合成注解后的初始化过程 * 自定义后置处理器以拦截原始在转为待合成注解后的初始化过程
* *
* <p>合成注解允许通过{@link #syntheticAnnotation(Class)}合成一个指定的注解对象 * <p>合成注解允许通过{@link #synthesize(Class)}合成一个指定的注解对象
* 该方法返回的注解对象可能是原始的注解对象也有可能通过动态代理的方式生成 * 该方法返回的注解对象可能是原始的注解对象也有可能通过动态代理的方式生成
* 该对象实例的属性不一定来自对象本身而是来自于经过{@link SynthesizedAnnotationAttributeProcessor} * 该对象实例的属性不一定来自对象本身而是来自于经过{@link SynthesizedAnnotationAttributeProcessor}
* 处理后的用于合成当前实例的全部关联注解的相关属性<br> * 处理后的用于合成当前实例的全部关联注解的相关属性<br>
@ -37,9 +37,9 @@ import java.util.Collection;
* @see SynthesizedAnnotationSelector * @see SynthesizedAnnotationSelector
* @see SynthesizedAnnotationAttributeProcessor * @see SynthesizedAnnotationAttributeProcessor
* @see SynthesizedAnnotationPostProcessor * @see SynthesizedAnnotationPostProcessor
* @see SyntheticMetaAnnotation * @see SynthesizedMetaAnnotationAggregator
*/ */
public interface SyntheticAnnotation extends Annotation, AnnotatedElement { public interface SynthesizedAnnotationAggregator extends Annotation, AnnotationAggregator {
/** /**
* 获取合成注解选择器 * 获取合成注解选择器
@ -53,14 +53,14 @@ public interface SyntheticAnnotation extends Annotation, AnnotatedElement {
* *
* @return 合成注解属性处理器 * @return 合成注解属性处理器
*/ */
SynthesizedAnnotationAttributeProcessor getAttributeProcessor(); SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor();
/** /**
* 获取合成注解属性后置处理器 * 获取合成注解属性后置处理器
* *
* @return 合成注解属性后置处理器 * @return 合成注解属性后置处理器
*/ */
Collection<SynthesizedAnnotationPostProcessor> getSynthesizedAnnotationAttributePostProcessors(); Collection<SynthesizedAnnotationPostProcessor> getAnnotationAttributePostProcessors();
/** /**
* 获取已合成的注解 * 获取已合成的注解
@ -75,7 +75,7 @@ public interface SyntheticAnnotation extends Annotation, AnnotatedElement {
* *
* @return 合成注解 * @return 合成注解
*/ */
Collection<SynthesizedAnnotation> getAllSyntheticAnnotations(); Collection<SynthesizedAnnotation> getAllSynthesizedAnnotation();
/** /**
* 获取当前的注解类型 * 获取当前的注解类型
@ -87,33 +87,6 @@ public interface SyntheticAnnotation extends Annotation, AnnotatedElement {
return this.getClass(); return this.getClass();
} }
/**
* 获取指定注解对象
*
* @param annotationType 注解类型
* @param <T> 注解类型
* @return 注解对象
*/
@Override
<T extends Annotation> T getAnnotation(Class<T> annotationType);
/**
* 是否存在指定注解
*
* @param annotationType 注解类型
* @return 是否
*/
@Override
boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/**
* 获取全部注解
*
* @return 注解对象
*/
@Override
Annotation[] getAnnotations();
/** /**
* 获取合成注解 * 获取合成注解
* *
@ -121,16 +94,7 @@ public interface SyntheticAnnotation extends Annotation, AnnotatedElement {
* @param <T> 注解类型 * @param <T> 注解类型
* @return 类型 * @return 类型
*/ */
<T extends Annotation> T syntheticAnnotation(Class<T> annotationType); <T extends Annotation> T synthesize(Class<T> annotationType);
/**
* 获取属性值
*
* @param attributeName 属性名称
* @param attributeType 属性类型
* @return 属性值
*/
Object getAttribute(String attributeName, Class<?> attributeType);
/** /**
* 基于指定根注解构建包括其元注解在内的合成注解 * 基于指定根注解构建包括其元注解在内的合成注解
@ -139,8 +103,8 @@ public interface SyntheticAnnotation extends Annotation, AnnotatedElement {
* @param <T> 注解类型 * @param <T> 注解类型
* @return 合成注解 * @return 合成注解
*/ */
static <T extends Annotation> SyntheticAnnotation of(T rootAnnotation) { static <T extends Annotation> SynthesizedAnnotationAggregator of(T rootAnnotation) {
return new SyntheticMetaAnnotation(rootAnnotation); return new SynthesizedMetaAnnotationAggregator(rootAnnotation);
} }
} }

View File

@ -3,7 +3,7 @@ package cn.hutool.core.annotation;
import java.util.Collection; import java.util.Collection;
/** /**
* 合成注解属性选择器用于在{@link SyntheticAnnotation}中从指定类型的合成注解里获取到对应的属性值 * 合成注解属性选择器用于在{@link SynthesizedAnnotationAggregator}中从指定类型的合成注解里获取到对应的属性值
* *
* @author huangchengxing * @author huangchengxing
*/ */

View File

@ -5,7 +5,7 @@ import cn.hutool.core.comparator.CompareUtil;
import java.util.Comparator; import java.util.Comparator;
/** /**
* <p>被合成注解后置处理器用于在{@link SyntheticAnnotation}加载完所有待合成注解后 * <p>被合成注解后置处理器用于在{@link SynthesizedAnnotationAggregator}加载完所有待合成注解后
* 再对加载好的{@link SynthesizedAnnotation}进行后置处理<br> * 再对加载好的{@link SynthesizedAnnotation}进行后置处理<br>
* 当多个{@link SynthesizedAnnotationPostProcessor}需要一起执行时将按照{@link #order()}的返回值进行排序 * 当多个{@link SynthesizedAnnotationPostProcessor}需要一起执行时将按照{@link #order()}的返回值进行排序
* 该值更小的处理器将被优先执行 * 该值更小的处理器将被优先执行
@ -49,8 +49,8 @@ public interface SynthesizedAnnotationPostProcessor extends Comparable<Synthesiz
* 给定指定被合成注解与其所属的合成注解实例经过处理后返回最终 * 给定指定被合成注解与其所属的合成注解实例经过处理后返回最终
* *
* @param annotation 被合成的注解 * @param annotation 被合成的注解
* @param syntheticAnnotation 注解所属的合成注解 * @param synthesizedAnnotationAggregator 注解所属的合成注解
*/ */
void process(SynthesizedAnnotation annotation, SyntheticAnnotation syntheticAnnotation); void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator);
} }

View File

@ -2,7 +2,7 @@ package cn.hutool.core.annotation;
/** /**
* 注解选择器指定两个注解选择其中一个返回<br> * 注解选择器指定两个注解选择其中一个返回<br>
* 该接口用于在{@link SyntheticAnnotation}中用于从一批相同的注解对象中筛选最终用于合成注解对象 * 该接口用于在{@link SynthesizedAnnotationAggregator}中用于从一批相同的注解对象中筛选最终用于合成注解对象
* *
* @author huangchengxing * @author huangchengxing
*/ */

View File

@ -15,10 +15,10 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* {@link SyntheticAnnotation}的基本实现表示一个根注解与根注解上的多层元注解合成的注解 * {@link SynthesizedAnnotationAggregator}的基本实现表示一个根注解与根注解上的多层元注解的聚合状态
* *
* <p>假设现有注解AA上存在元注解BB上存在元注解C则对注解A进行解析 * <p>假设现有注解AA上存在元注解BB上存在元注解C则对注解A进行解析
* 将得到包含根注解A以及其元注解BC在内的合成元注解{@link SyntheticMetaAnnotation} * 将得到包含根注解A以及其元注解BC在内的合成元注解聚合{@link SynthesizedMetaAnnotationAggregator}
* {@link AnnotatedElement}的角度来说得到的合成注解是一个同时承载有ABC三个注解对象的被注解元素 * {@link AnnotatedElement}的角度来说得到的合成注解是一个同时承载有ABC三个注解对象的被注解元素
* 因此通过调用{@link AnnotatedElement}的相关方法将返回对应符合语义的注解对象 * 因此通过调用{@link AnnotatedElement}的相关方法将返回对应符合语义的注解对象
* *
@ -39,8 +39,8 @@ import java.util.stream.Stream;
* </ul> * </ul>
* 若用户需要自行扩展则需要保证上述三个处理器被正确注入当前实例 * 若用户需要自行扩展则需要保证上述三个处理器被正确注入当前实例
* *
* <p>{@link SyntheticMetaAnnotation}支持通过{@link #getAttribute(String, Class)} * <p>{@link SynthesizedMetaAnnotationAggregator}支持通过{@link #getAttribute(String, Class)}
* 或通过{@link #syntheticAnnotation(Class)}获得注解代理对象后获取指定类型的注解属性值 * 或通过{@link #synthesize(Class)}获得注解代理对象后获取指定类型的注解属性值
* 返回的属性值将根据合成注解中对应原始注解属性上的{@link Alias}{@link Link}注解而有所变化 * 返回的属性值将根据合成注解中对应原始注解属性上的{@link Alias}{@link Link}注解而有所变化
* 通过当前实例获取属性值时将经过{@link SynthesizedAnnotationAttributeProcessor}的处理<br> * 通过当前实例获取属性值时将经过{@link SynthesizedAnnotationAttributeProcessor}的处理<br>
* 默认情况下实例将会注册{@link CacheableSynthesizedAnnotationAttributeProcessor} * 默认情况下实例将会注册{@link CacheableSynthesizedAnnotationAttributeProcessor}
@ -50,7 +50,7 @@ import java.util.stream.Stream;
* @see AnnotationUtil * @see AnnotationUtil
* @see SynthesizedAnnotationSelector * @see SynthesizedAnnotationSelector
*/ */
public class SyntheticMetaAnnotation implements SyntheticAnnotation { public class SynthesizedMetaAnnotationAggregator implements SynthesizedAnnotationAggregator {
/** /**
* 根注解即当前查找的注解 * 根注解即当前查找的注解
@ -84,7 +84,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* *
* @param source 源注解 * @param source 源注解
*/ */
public SyntheticMetaAnnotation(Annotation source) { public SynthesizedMetaAnnotationAggregator(Annotation source) {
this( this(
source, SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY, source, SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY,
new CacheableSynthesizedAnnotationAttributeProcessor(), new CacheableSynthesizedAnnotationAttributeProcessor(),
@ -103,7 +103,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* @param annotationSelector 合成注解选择器 * @param annotationSelector 合成注解选择器
* @param attributeProcessor 注解属性处理器 * @param attributeProcessor 注解属性处理器
*/ */
public SyntheticMetaAnnotation( public SynthesizedMetaAnnotationAggregator(
Annotation annotation, Annotation annotation,
SynthesizedAnnotationSelector annotationSelector, SynthesizedAnnotationSelector annotationSelector,
SynthesizedAnnotationAttributeProcessor attributeProcessor, SynthesizedAnnotationAttributeProcessor attributeProcessor,
@ -137,15 +137,6 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
return source; return source;
} }
/**
* 获取已解析的元注解信息
*
* @return 已解析的元注解信息
*/
Map<Class<? extends Annotation>, SynthesizedAnnotation> getMetaAnnotationMap() {
return metaAnnotationMap;
}
/** /**
* 获取合成注解选择器 * 获取合成注解选择器
* *
@ -162,7 +153,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* @return 合成注解属性处理器 * @return 合成注解属性处理器
*/ */
@Override @Override
public SynthesizedAnnotationAttributeProcessor getAttributeProcessor() { public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
return this.attributeProcessor; return this.attributeProcessor;
} }
@ -172,7 +163,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* @return 合成注解属性后置处理器 * @return 合成注解属性后置处理器
*/ */
@Override @Override
public Collection<SynthesizedAnnotationPostProcessor> getSynthesizedAnnotationAttributePostProcessors() { public Collection<SynthesizedAnnotationPostProcessor> getAnnotationAttributePostProcessors() {
return this.postProcessors; return this.postProcessors;
} }
@ -193,7 +184,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* @return 合成注解 * @return 合成注解
*/ */
@Override @Override
public Collection<SynthesizedAnnotation> getAllSyntheticAnnotations() { public Collection<SynthesizedAnnotation> getAllSynthesizedAnnotation() {
return metaAnnotationMap.values(); return metaAnnotationMap.values();
} }
@ -254,10 +245,10 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* *
* @param annotationType 注解类型 * @param annotationType 注解类型
* @return 合成注解对象 * @return 合成注解对象
* @see SyntheticAnnotationProxy#create(Class, SyntheticAnnotation) * @see SyntheticAnnotationProxy#create(Class, SynthesizedAnnotationAggregator)
*/ */
@Override @Override
public <T extends Annotation> T syntheticAnnotation(Class<T> annotationType) { public <T extends Annotation> T synthesize(Class<T> annotationType) {
return SyntheticAnnotationProxy.create(annotationType, this); return SyntheticAnnotationProxy.create(annotationType, this);
} }
@ -299,14 +290,14 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
*/ */
public static class MetaAnnotation implements Annotation, SynthesizedAnnotation { public static class MetaAnnotation implements Annotation, SynthesizedAnnotation {
private final SyntheticAnnotation owner; private final SynthesizedAnnotationAggregator owner;
private final Annotation root; private final Annotation root;
private final Annotation annotation; private final Annotation annotation;
private final Map<String, AnnotationAttribute> attributeMethodCaches; private final Map<String, AnnotationAttribute> attributeMethodCaches;
private final int verticalDistance; private final int verticalDistance;
private final int horizontalDistance; private final int horizontalDistance;
public MetaAnnotation(SyntheticAnnotation owner, Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) { public MetaAnnotation(SynthesizedAnnotationAggregator owner, Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) {
this.owner = owner; this.owner = owner;
this.root = root; this.root = root;
this.annotation = annotation; this.annotation = annotation;
@ -323,7 +314,7 @@ public class SyntheticMetaAnnotation implements SyntheticAnnotation {
* @return 合成注解 * @return 合成注解
*/ */
@Override @Override
public SyntheticAnnotation getOwner() { public SynthesizedAnnotationAggregator getOwner() {
return owner; return owner;
} }

View File

@ -38,18 +38,18 @@ class SyntheticAnnotationProxy implements InvocationHandler {
/** /**
* 创建一个代理注解生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类 * 创建一个代理注解生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类
* <ul> * <ul>
* <li>当作为{@code annotationType}所指定的类型使用时其属性将通过合成它的{@link SyntheticAnnotation}获取</li> * <li>当作为{@code annotationType}所指定的类型使用时其属性将通过合成它的{@link SynthesizedAnnotationAggregator}获取</li>
* <li>当作为{@link SyntheticProxyAnnotation}{@link SynthesizedAnnotation}使用时将可以获得原始注解实例的相关信息</li> * <li>当作为{@link SyntheticProxyAnnotation}{@link SynthesizedAnnotation}使用时将可以获得原始注解实例的相关信息</li>
* </ul> * </ul>
* *
* @param annotationType 注解类型 * @param annotationType 注解类型
* @param syntheticAnnotation 合成注解 * @param synthesizedAnnotationAggregator 合成注解
* @return 代理注解 * @return 代理注解
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends Annotation> T create( static <T extends Annotation> T create(
Class<T> annotationType, SyntheticAnnotation syntheticAnnotation) { Class<T> annotationType, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) {
final SynthesizedAnnotation annotation = syntheticAnnotation.getSynthesizedAnnotation(annotationType); final SynthesizedAnnotation annotation = synthesizedAnnotationAggregator.getSynthesizedAnnotation(annotationType);
if (ObjectUtil.isNull(annotation)) { if (ObjectUtil.isNull(annotation)) {
return null; return null;
} }
@ -83,7 +83,6 @@ class SyntheticAnnotationProxy implements InvocationHandler {
methods.put("getSyntheticAnnotation", (method, args) -> proxyGetSyntheticAnnotation()); methods.put("getSyntheticAnnotation", (method, args) -> proxyGetSyntheticAnnotation());
methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation()); methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation());
methods.put("getRoot", (method, args) -> annotation.getRoot()); methods.put("getRoot", (method, args) -> annotation.getRoot());
methods.put("isRoot", (method, args) -> annotation.isRoot());
methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance()); methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance());
methods.put("getHorizontalDistance", (method, args) -> annotation.getHorizontalDistance()); methods.put("getHorizontalDistance", (method, args) -> annotation.getHorizontalDistance());
methods.put("hasAttribute", (method, args) -> annotation.hasAttribute((String)args[0], (Class<?>)args[1])); methods.put("hasAttribute", (method, args) -> annotation.hasAttribute((String)args[0], (Class<?>)args[1]));
@ -135,7 +134,7 @@ class SyntheticAnnotationProxy implements InvocationHandler {
* *
* @return 合成注解 * @return 合成注解
*/ */
SyntheticAnnotation getSyntheticAnnotation(); SynthesizedAnnotationAggregator getSyntheticAnnotation();
/** /**
* 获取该代理注解对应的已合成注解 * 获取该代理注解对应的已合成注解

View File

@ -9,7 +9,7 @@ import java.lang.annotation.Annotation;
import java.util.Comparator; import java.util.Comparator;
/** /**
* {@link SyntheticAnnotation}相关工具用于内部使用 * {@link SynthesizedAnnotationAggregator}相关工具用于内部使用
* *
* @author huangchengxing * @author huangchengxing
*/ */
@ -33,12 +33,12 @@ class SyntheticAnnotationUtil {
* 从合成注解中获取{@link Link#type()}指定的注解对象 * 从合成注解中获取{@link Link#type()}指定的注解对象
* *
* @param annotation {@link Link}注解 * @param annotation {@link Link}注解
* @param syntheticAnnotation 合成注解 * @param synthesizedAnnotationAggregator 合成注解
*/ */
static SynthesizedAnnotation getLinkedAnnotation( static SynthesizedAnnotation getLinkedAnnotation(
Link annotation, SyntheticAnnotation syntheticAnnotation, Class<? extends Annotation> defaultType) { Link annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, Class<? extends Annotation> defaultType) {
final Class<?> targetAnnotationType = getLinkedAnnotationType(annotation, defaultType); final Class<?> targetAnnotationType = getLinkedAnnotationType(annotation, defaultType);
return syntheticAnnotation.getSynthesizedAnnotation(targetAnnotationType); return synthesizedAnnotationAggregator.getSynthesizedAnnotation(targetAnnotationType);
} }
/** /**
@ -68,6 +68,17 @@ class SyntheticAnnotationUtil {
); );
} }
/**
* 检查{@link Link}指向的注解属性是否就是本身
*
* @param original {@link Link}注解的属性
* @param linked {@link Link}指向的注解属性
*/
static void checkLinkedSelf(AnnotationAttribute original, AnnotationAttribute linked) {
boolean linkSelf = (original == linked) || ObjectUtil.equals(original.getAttribute(), linked.getAttribute());
Assert.isFalse(linkSelf, "cannot link self [{}]", original.getAttribute());
}
/** /**
* 检查{@link Link}指向的注解属性是否存在 * 检查{@link Link}指向的注解属性是否存在
* *

View File

@ -27,7 +27,7 @@ import java.util.Collection;
* @see AliasedAnnotationAttribute * @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute * @see MirroredAnnotationAttribute
*/ */
public interface AnnotationAttributeWrapper extends AnnotationAttribute { public interface WrappedAnnotationAttribute extends AnnotationAttribute {
// =========================== 新增方法 =========================== // =========================== 新增方法 ===========================
@ -89,9 +89,7 @@ public interface AnnotationAttributeWrapper extends AnnotationAttribute {
* @return 该注解属性的值是否等于默认值 * @return 该注解属性的值是否等于默认值
*/ */
@Override @Override
default boolean isValueEquivalentToDefaultValue() { boolean isValueEquivalentToDefaultValue();
return getOriginal().isValueEquivalentToDefaultValue() && getLinked().isValueEquivalentToDefaultValue();
}
/** /**
* 获取属性类型 * 获取属性类型
@ -115,7 +113,7 @@ public interface AnnotationAttributeWrapper extends AnnotationAttribute {
} }
/** /**
* 当前注解属性是否已经被{@link AnnotationAttributeWrapper}包装 * 当前注解属性是否已经被{@link WrappedAnnotationAttribute}包装
* *
* @return boolean * @return boolean
*/ */

View File

@ -8,7 +8,7 @@ import org.junit.Test;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
public class AbstractAnnotationAttributeWrapperTest { public class AbstractWrappedAnnotationAttributeTest {
@Test @Test
public void workTest() { public void workTest() {
@ -17,7 +17,9 @@ public class AbstractAnnotationAttributeWrapperTest {
CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod); CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
Method nameMethod = ReflectUtil.getMethod(AnnotationForTest1.class, "name1"); Method nameMethod = ReflectUtil.getMethod(AnnotationForTest1.class, "name1");
CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod); CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
TestAnnotationAttributeWrapper nameWrapper = new TestAnnotationAttributeWrapper(nameAttribute, valueAttribute); AbstractWrappedAnnotationAttribute nameWrapper = new TestWrappedAnnotationAttribute(nameAttribute, valueAttribute);
Assert.assertEquals(nameWrapper.getAnnotation(), annotation);
// 注解属性 // 注解属性
Assert.assertEquals(annotation, nameWrapper.getAnnotation()); Assert.assertEquals(annotation, nameWrapper.getAnnotation());
@ -40,7 +42,7 @@ public class AbstractAnnotationAttributeWrapperTest {
CacheableAnnotationAttribute value1Attribute = new CacheableAnnotationAttribute(annotation1, value1Method); CacheableAnnotationAttribute value1Attribute = new CacheableAnnotationAttribute(annotation1, value1Method);
Method name1Method = ReflectUtil.getMethod(AnnotationForTest1.class, "name1"); Method name1Method = ReflectUtil.getMethod(AnnotationForTest1.class, "name1");
CacheableAnnotationAttribute name1Attribute = new CacheableAnnotationAttribute(annotation1, name1Method); CacheableAnnotationAttribute name1Attribute = new CacheableAnnotationAttribute(annotation1, name1Method);
TestAnnotationAttributeWrapper wrapper1 = new TestAnnotationAttributeWrapper(name1Attribute, value1Attribute); AbstractWrappedAnnotationAttribute wrapper1 = new TestWrappedAnnotationAttribute(name1Attribute, value1Attribute);
Assert.assertEquals(name1Attribute, wrapper1.getNonWrappedOriginal()); Assert.assertEquals(name1Attribute, wrapper1.getNonWrappedOriginal());
Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute), wrapper1.getAllLinkedNonWrappedAttributes()); Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute), wrapper1.getAllLinkedNonWrappedAttributes());
@ -48,7 +50,7 @@ public class AbstractAnnotationAttributeWrapperTest {
Annotation annotation2 = ClassForTest1.class.getAnnotation(AnnotationForTest2.class); Annotation annotation2 = ClassForTest1.class.getAnnotation(AnnotationForTest2.class);
Method value2Method = ReflectUtil.getMethod(AnnotationForTest2.class, "value2"); Method value2Method = ReflectUtil.getMethod(AnnotationForTest2.class, "value2");
CacheableAnnotationAttribute value2Attribute = new CacheableAnnotationAttribute(annotation2, value2Method); CacheableAnnotationAttribute value2Attribute = new CacheableAnnotationAttribute(annotation2, value2Method);
TestAnnotationAttributeWrapper wrapper2 = new TestAnnotationAttributeWrapper(wrapper1, value2Attribute); AbstractWrappedAnnotationAttribute wrapper2 = new TestWrappedAnnotationAttribute(wrapper1, value2Attribute);
Assert.assertEquals(name1Attribute, wrapper2.getNonWrappedOriginal()); Assert.assertEquals(name1Attribute, wrapper2.getNonWrappedOriginal());
Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute, value2Attribute), wrapper2.getAllLinkedNonWrappedAttributes()); Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute, value2Attribute), wrapper2.getAllLinkedNonWrappedAttributes());
@ -56,20 +58,25 @@ public class AbstractAnnotationAttributeWrapperTest {
Annotation annotation3 = ClassForTest1.class.getAnnotation(AnnotationForTest3.class); Annotation annotation3 = ClassForTest1.class.getAnnotation(AnnotationForTest3.class);
Method value3Method = ReflectUtil.getMethod(AnnotationForTest3.class, "value3"); Method value3Method = ReflectUtil.getMethod(AnnotationForTest3.class, "value3");
CacheableAnnotationAttribute value3Attribute = new CacheableAnnotationAttribute(annotation3, value3Method); CacheableAnnotationAttribute value3Attribute = new CacheableAnnotationAttribute(annotation3, value3Method);
TestAnnotationAttributeWrapper wrapper3 = new TestAnnotationAttributeWrapper(value3Attribute, wrapper2); AbstractWrappedAnnotationAttribute wrapper3 = new TestWrappedAnnotationAttribute(value3Attribute, wrapper2);
Assert.assertEquals(value3Attribute, wrapper3.getNonWrappedOriginal()); Assert.assertEquals(value3Attribute, wrapper3.getNonWrappedOriginal());
Assert.assertEquals(CollUtil.newArrayList(value3Attribute, name1Attribute, value1Attribute, value2Attribute), wrapper3.getAllLinkedNonWrappedAttributes()); Assert.assertEquals(CollUtil.newArrayList(value3Attribute, name1Attribute, value1Attribute, value2Attribute), wrapper3.getAllLinkedNonWrappedAttributes());
} }
static class TestAnnotationAttributeWrapper extends AbstractAnnotationAttributeWrapper { static class TestWrappedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
protected TestAnnotationAttributeWrapper(AnnotationAttribute original, AnnotationAttribute linked) { protected TestWrappedAnnotationAttribute(AnnotationAttribute original, AnnotationAttribute linked) {
super(original, linked); super(original, linked);
} }
@Override @Override
public Object getValue() { public Object getValue() {
return linked.getValue(); return linked.getValue();
} }
@Override
public boolean isValueEquivalentToDefaultValue() {
return getOriginal().isValueEquivalentToDefaultValue() && getLinked().isValueEquivalentToDefaultValue();
}
} }
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -0,0 +1,190 @@
package cn.hutool.core.annotation;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
public class AliasAttributePostProcessorTest {
@Test
public void processTest() {
AliasAttributePostProcessor processor = new AliasAttributePostProcessor();
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap);
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
Assert.assertTrue(valueAttribute.isWrapped());
Assert.assertEquals(ForceAliasedAnnotationAttribute.class, valueAttribute.getClass());
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
Assert.assertFalse(nameAttribute.isWrapped());
Assert.assertEquals(CacheableAnnotationAttribute.class, nameAttribute.getClass());
Assert.assertEquals(nameAttribute, ((WrappedAnnotationAttribute)valueAttribute).getLinked());
}
@AnnotationForTest
static class ClassForTest {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@interface AnnotationForTest {
@Alias("name")
String value() default "";
String name() default "";
}
static class TestSynthesizedAnnotationAggregator implements SynthesizedAnnotationAggregator {
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
public TestSynthesizedAnnotationAggregator(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
this.annotationMap = annotationMap;
}
@Override
public SynthesizedAnnotationSelector getAnnotationSelector() {
return null;
}
@Override
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
return null;
}
@Override
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationAttributePostProcessors() {
return null;
}
@Override
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
return annotationMap.get(annotationType);
}
@Override
public Collection<SynthesizedAnnotation> getAllSynthesizedAnnotation() {
return null;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return null;
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return false;
}
@Override
public Annotation[] getAnnotations() {
return new Annotation[0];
}
@Override
public <T extends Annotation> T synthesize(Class<T> annotationType) {
return null;
}
@Override
public Object getAttribute(String attributeName, Class<?> attributeType) {
return null;
}
@Override
public Annotation[] getDeclaredAnnotations() {
return new Annotation[0];
}
}
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
private final Annotation annotation;
private final SynthesizedAnnotationAggregator owner;
private final Map<String, AnnotationAttribute> attributeMap;
public TestSynthesizedAnnotation(SynthesizedAnnotationAggregator owner, Annotation annotation) {
this.owner = owner;
this.attributeMap = new HashMap<>();
this.annotation = annotation;
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
}
}
@Override
public SynthesizedAnnotationAggregator getOwner() {
return owner;
}
@Override
public Object getRoot() {
return null;
}
@Override
public Annotation getAnnotation() {
return annotation;
}
@Override
public int getVerticalDistance() {
return 0;
}
@Override
public int getHorizontalDistance() {
return 0;
}
@Override
public boolean hasAttribute(String attributeName, Class<?> returnType) {
return false;
}
@Override
public Map<String, AnnotationAttribute> getAttributes() {
return attributeMap;
}
@Override
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
attributeMap.put(attributeName, attribute);
}
@Override
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
if (ObjectUtil.isNotNull(annotationAttribute)) {
attributeMap.put(attributeName, operator.apply(annotationAttribute));
}
}
@Override
public Object getAttributeValue(String attributeName) {
return null;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
}
}

View File

@ -0,0 +1,218 @@
package cn.hutool.core.annotation;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
public class AliasForLinkAttributePostProcessorTest {
@Test
public void processForceAliasForTest() {
AliasForLinkAttributePostProcessor processor = new AliasForLinkAttributePostProcessor();
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap);
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
Assert.assertFalse(valueAttribute.isWrapped());
Assert.assertEquals(CacheableAnnotationAttribute.class, valueAttribute.getClass());
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
Assert.assertTrue(nameAttribute.isWrapped());
Assert.assertEquals(ForceAliasedAnnotationAttribute.class, nameAttribute.getClass());
Assert.assertEquals(valueAttribute, ((WrappedAnnotationAttribute)nameAttribute).getLinked());
}
@Test
public void processAliasForTest() {
AliasForLinkAttributePostProcessor processor = new AliasForLinkAttributePostProcessor();
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap);
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value2");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value2"), valueAttribute.getAttribute());
Assert.assertFalse(valueAttribute.isWrapped());
Assert.assertEquals(CacheableAnnotationAttribute.class, valueAttribute.getClass());
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name2");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name2"), nameAttribute.getAttribute());
Assert.assertTrue(nameAttribute.isWrapped());
Assert.assertEquals(AliasedAnnotationAttribute.class, nameAttribute.getClass());
Assert.assertEquals(valueAttribute, ((WrappedAnnotationAttribute)nameAttribute).getLinked());
}
@AnnotationForTest
static class ClassForTest {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@interface AnnotationForTest {
@Link(attribute = "name", type = RelationType.FORCE_ALIAS_FOR)
String value() default "";
String name() default "";
@Link(attribute = "name2", type = RelationType.ALIAS_FOR)
String value2() default "";
String name2() default "";
}
static class TestSynthesizedAnnotationAggregator implements SynthesizedAnnotationAggregator {
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
public TestSynthesizedAnnotationAggregator(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
this.annotationMap = annotationMap;
}
@Override
public SynthesizedAnnotationSelector getAnnotationSelector() {
return null;
}
@Override
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
return null;
}
@Override
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationAttributePostProcessors() {
return null;
}
@Override
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
return annotationMap.get(annotationType);
}
@Override
public Collection<SynthesizedAnnotation> getAllSynthesizedAnnotation() {
return null;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return null;
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return false;
}
@Override
public Annotation[] getAnnotations() {
return new Annotation[0];
}
@Override
public <T extends Annotation> T synthesize(Class<T> annotationType) {
return null;
}
@Override
public Object getAttribute(String attributeName, Class<?> attributeType) {
return null;
}
@Override
public Annotation[] getDeclaredAnnotations() {
return new Annotation[0];
}
}
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
private final Annotation annotation;
private final SynthesizedAnnotationAggregator owner;
private final Map<String, AnnotationAttribute> attributeMap;
public TestSynthesizedAnnotation(SynthesizedAnnotationAggregator owner, Annotation annotation) {
this.owner = owner;
this.attributeMap = new HashMap<>();
this.annotation = annotation;
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
}
}
@Override
public SynthesizedAnnotationAggregator getOwner() {
return owner;
}
@Override
public Object getRoot() {
return null;
}
@Override
public Annotation getAnnotation() {
return annotation;
}
@Override
public int getVerticalDistance() {
return 0;
}
@Override
public int getHorizontalDistance() {
return 0;
}
@Override
public boolean hasAttribute(String attributeName, Class<?> returnType) {
return false;
}
@Override
public Map<String, AnnotationAttribute> getAttributes() {
return attributeMap;
}
@Override
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
attributeMap.put(attributeName, attribute);
}
@Override
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
if (ObjectUtil.isNotNull(annotationAttribute)) {
attributeMap.put(attributeName, operator.apply(annotationAttribute));
}
}
@Override
public Object getAttributeValue(String attributeName) {
return null;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
}
}

View File

@ -17,15 +17,16 @@ public class AliasedAnnotationAttributeTest {
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod); final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name"); final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod); final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
final AliasedAnnotationAttribute annotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute); final AliasedAnnotationAttribute valueAnnotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute);
// 注解属性 // 注解属性
Assert.assertEquals(annotation, annotationAttribute.getAnnotation()); Assert.assertEquals(annotation, valueAnnotationAttribute.getAnnotation());
Assert.assertEquals(annotation.annotationType(), annotationAttribute.getAnnotationType()); Assert.assertEquals(annotation.annotationType(), valueAnnotationAttribute.getAnnotationType());
// 方法属性 // 方法属性
Assert.assertEquals(valueMethod.getName(), annotationAttribute.getAttributeName()); Assert.assertEquals(valueMethod.getAnnotation(Alias.class), valueAnnotationAttribute.getAnnotation(Alias.class));
Assert.assertEquals(nameMethod.getReturnType(), annotationAttribute.getAttributeType()); Assert.assertEquals(valueMethod.getName(), valueAnnotationAttribute.getAttributeName());
Assert.assertEquals(nameMethod.getReturnType(), valueAnnotationAttribute.getAttributeType());
} }
@Test @Test
@ -63,6 +64,7 @@ public class AliasedAnnotationAttributeTest {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE }) @Target({ ElementType.METHOD, ElementType.TYPE })
@interface AnnotationForTest { @interface AnnotationForTest {
@Alias("value")
String value() default ""; String value() default "";
String name() default ""; String name() default "";
} }

View File

@ -0,0 +1,100 @@
package cn.hutool.core.annotation;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.util.ClassUtil;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Map;
import java.util.function.UnaryOperator;
public class CacheableSynthesizedAnnotationAttributeProcessorTest {
@Test
public void getAttributeValueTest() {
CacheableSynthesizedAnnotationAttributeProcessor processor = new CacheableSynthesizedAnnotationAttributeProcessor();
Map<String, Object> values1 = MapBuilder.<String, Object> create().put("name", "name1").put("value", 111).build();
SynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(1, 0, values1);
Map<String, Object> values2 = MapBuilder.<String, Object> create().put("name", "name2").put("value", "value2").build();
SynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0, values2);
Assert.assertEquals("name2", processor.getAttributeValue("name", String.class, Arrays.asList(annotation1, annotation2)));
Assert.assertEquals(Integer.valueOf(111), processor.getAttributeValue("value", Integer.class, Arrays.asList(annotation1, annotation2)));
}
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
private final int verticalDistance;
private final int horizontalDistance;
private final Map<String, Object> value;
public TestSynthesizedAnnotation(int verticalDistance, int horizontalDistance, Map<String, Object> value) {
this.verticalDistance = verticalDistance;
this.horizontalDistance = horizontalDistance;
this.value = value;
}
@Override
public SynthesizedAnnotationAggregator getOwner() {
return null;
}
@Override
public Object getRoot() {
return null;
}
@Override
public Annotation getAnnotation() {
return null;
}
@Override
public int getVerticalDistance() {
return verticalDistance;
}
@Override
public int getHorizontalDistance() {
return horizontalDistance;
}
@Override
public boolean hasAttribute(String attributeName, Class<?> returnType) {
return Opt.ofNullable(value.get(attributeName))
.map(t -> ClassUtil.isAssignable(returnType, t.getClass()))
.orElse(false);
}
@Override
public Map<String, AnnotationAttribute> getAttributes() {
return null;
}
@Override
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
}
@Override
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
}
@Override
public Object getAttributeValue(String attributeName) {
return value.get(attributeName);
}
@Override
public Class<? extends Annotation> annotationType() {
return null;
}
}
}

View File

@ -0,0 +1,192 @@
package cn.hutool.core.annotation;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
public class MirrorLinkAttributePostProcessorTest {
@Test
public void processTest() {
MirrorLinkAttributePostProcessor processor = new MirrorLinkAttributePostProcessor();
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap);
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
Assert.assertTrue(valueAttribute.isWrapped());
Assert.assertEquals(MirroredAnnotationAttribute.class, valueAttribute.getClass());
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
Assert.assertTrue(nameAttribute.isWrapped());
Assert.assertEquals(MirroredAnnotationAttribute.class, nameAttribute.getClass());
Assert.assertEquals(((WrappedAnnotationAttribute)nameAttribute).getLinked(), ((WrappedAnnotationAttribute)valueAttribute).getOriginal());
Assert.assertEquals(((WrappedAnnotationAttribute)nameAttribute).getOriginal(), ((WrappedAnnotationAttribute)valueAttribute).getLinked());
}
@AnnotationForTest
static class ClassForTest {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@interface AnnotationForTest {
@Link(attribute = "name", type = RelationType.MIRROR_FOR)
String value() default "";
@Link(attribute = "value", type = RelationType.MIRROR_FOR)
String name() default "";
}
static class TestSynthesizedAnnotationAggregator implements SynthesizedAnnotationAggregator {
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
public TestSynthesizedAnnotationAggregator(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
this.annotationMap = annotationMap;
}
@Override
public SynthesizedAnnotationSelector getAnnotationSelector() {
return null;
}
@Override
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
return null;
}
@Override
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationAttributePostProcessors() {
return null;
}
@Override
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
return annotationMap.get(annotationType);
}
@Override
public Collection<SynthesizedAnnotation> getAllSynthesizedAnnotation() {
return null;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return null;
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return false;
}
@Override
public Annotation[] getAnnotations() {
return new Annotation[0];
}
@Override
public <T extends Annotation> T synthesize(Class<T> annotationType) {
return null;
}
@Override
public Object getAttribute(String attributeName, Class<?> attributeType) {
return null;
}
@Override
public Annotation[] getDeclaredAnnotations() {
return new Annotation[0];
}
}
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
private final Annotation annotation;
private final SynthesizedAnnotationAggregator owner;
private final Map<String, AnnotationAttribute> attributeMap;
public TestSynthesizedAnnotation(SynthesizedAnnotationAggregator owner, Annotation annotation) {
this.owner = owner;
this.attributeMap = new HashMap<>();
this.annotation = annotation;
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
}
}
@Override
public SynthesizedAnnotationAggregator getOwner() {
return owner;
}
@Override
public Object getRoot() {
return null;
}
@Override
public Annotation getAnnotation() {
return annotation;
}
@Override
public int getVerticalDistance() {
return 0;
}
@Override
public int getHorizontalDistance() {
return 0;
}
@Override
public boolean hasAttribute(String attributeName, Class<?> returnType) {
return false;
}
@Override
public Map<String, AnnotationAttribute> getAttributes() {
return attributeMap;
}
@Override
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
attributeMap.put(attributeName, attribute);
}
@Override
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
if (ObjectUtil.isNotNull(annotationAttribute)) {
attributeMap.put(attributeName, operator.apply(annotationAttribute));
}
}
@Override
public Object getAttributeValue(String attributeName) {
return null;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
}
}

View File

@ -10,8 +10,8 @@ import java.util.function.UnaryOperator;
public class SynthesizedAnnotationSelectorTest { public class SynthesizedAnnotationSelectorTest {
@Test @Test
public void nearestAndOldestPriorityTest() { public void chooseTest() {
final SynthesizedAnnotationSelector selector = SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY; final SynthesizedAnnotationSelector.NearestAndOldestPrioritySelector selector = (SynthesizedAnnotationSelector.NearestAndOldestPrioritySelector)SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY;
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
@ -28,7 +28,7 @@ public class SynthesizedAnnotationSelectorTest {
@Test @Test
public void nearestAndNewestPriorityTest() { public void nearestAndNewestPriorityTest() {
final SynthesizedAnnotationSelector selector = SynthesizedAnnotationSelector.NEAREST_AND_NEWEST_PRIORITY; final SynthesizedAnnotationSelector.NearestAndNewestPrioritySelector selector = (SynthesizedAnnotationSelector.NearestAndNewestPrioritySelector)SynthesizedAnnotationSelector.NEAREST_AND_NEWEST_PRIORITY;
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
@ -45,7 +45,7 @@ public class SynthesizedAnnotationSelectorTest {
@Test @Test
public void farthestAndOldestPriorityTest() { public void farthestAndOldestPriorityTest() {
final SynthesizedAnnotationSelector selector = SynthesizedAnnotationSelector.FARTHEST_AND_OLDEST_PRIORITY; final SynthesizedAnnotationSelector.FarthestAndOldestPrioritySelector selector = (SynthesizedAnnotationSelector.FarthestAndOldestPrioritySelector)SynthesizedAnnotationSelector.FARTHEST_AND_OLDEST_PRIORITY;
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
@ -62,7 +62,7 @@ public class SynthesizedAnnotationSelectorTest {
@Test @Test
public void farthestAndNewestPriorityTest() { public void farthestAndNewestPriorityTest() {
final SynthesizedAnnotationSelector selector = SynthesizedAnnotationSelector.FARTHEST_AND_NEWEST_PRIORITY; final SynthesizedAnnotationSelector.FarthestAndNewestPrioritySelector selector = (SynthesizedAnnotationSelector.FarthestAndNewestPrioritySelector)SynthesizedAnnotationSelector.FARTHEST_AND_NEWEST_PRIORITY;
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0); TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
@ -88,7 +88,7 @@ public class SynthesizedAnnotationSelectorTest {
} }
@Override @Override
public SyntheticAnnotation getOwner() { public SynthesizedAnnotationAggregator getOwner() {
return null; return null;
} }

View File

@ -9,7 +9,7 @@ import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
/** /**
* 合成注解{@link SyntheticMetaAnnotation}的测试用例 * 合成注解{@link SynthesizedMetaAnnotationAggregator}的测试用例
* *
* @author huangchengxing * @author huangchengxing
*/ */
@ -22,10 +22,10 @@ public class SyntheticMetaAnnotationTest {
final GrandParentAnnotation grandParentAnnotation = ChildAnnotation.class.getAnnotation(GrandParentAnnotation.class); final GrandParentAnnotation grandParentAnnotation = ChildAnnotation.class.getAnnotation(GrandParentAnnotation.class);
final ParentAnnotation parentAnnotation = ChildAnnotation.class.getAnnotation(ParentAnnotation.class); final ParentAnnotation parentAnnotation = ChildAnnotation.class.getAnnotation(ParentAnnotation.class);
final ChildAnnotation childAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class); final ChildAnnotation childAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
final SyntheticMetaAnnotation syntheticMetaAnnotation = new SyntheticMetaAnnotation(childAnnotation); final SynthesizedMetaAnnotationAggregator syntheticMetaAnnotation = new SynthesizedMetaAnnotationAggregator(childAnnotation);
// Annotation & AnnotatedElement // Annotation & AnnotatedElement
Assert.assertEquals(SyntheticMetaAnnotation.class, syntheticMetaAnnotation.annotationType()); Assert.assertEquals(SynthesizedMetaAnnotationAggregator.class, syntheticMetaAnnotation.annotationType());
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class)); Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class)); Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class)); Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
@ -42,15 +42,20 @@ public class SyntheticMetaAnnotationTest {
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(GrandParentAnnotation.class)); Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(GrandParentAnnotation.class));
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ParentAnnotation.class)); Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ParentAnnotation.class));
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ChildAnnotation.class)); Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ChildAnnotation.class));
Assert.assertEquals(3, syntheticMetaAnnotation.getAllSyntheticAnnotations().size()); Assert.assertEquals(3, syntheticMetaAnnotation.getAllSynthesizedAnnotation().size());
// 属性
Assert.assertEquals(SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY, syntheticMetaAnnotation.getAnnotationSelector());
Assert.assertEquals(CacheableSynthesizedAnnotationAttributeProcessor.class, syntheticMetaAnnotation.getAnnotationAttributeProcessor().getClass());
Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotationAttributePostProcessors().size());
} }
@Test @Test
public void synthesisAnnotationAttributeTest() { public void synthesisAnnotationAttributeTest() {
final ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class); final ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
SyntheticMetaAnnotation syntheticMetaAnnotation = new SyntheticMetaAnnotation(rootAnnotation); SynthesizedMetaAnnotationAggregator syntheticMetaAnnotation = new SynthesizedMetaAnnotationAggregator(rootAnnotation);
Assert.assertEquals(syntheticMetaAnnotation.getSource(), rootAnnotation); Assert.assertEquals(syntheticMetaAnnotation.getSource(), rootAnnotation);
Assert.assertEquals(syntheticMetaAnnotation.annotationType(), SyntheticMetaAnnotation.class); Assert.assertEquals(syntheticMetaAnnotation.annotationType(), SynthesizedMetaAnnotationAggregator.class);
Assert.assertEquals(1, syntheticMetaAnnotation.getDeclaredAnnotations().length); Assert.assertEquals(1, syntheticMetaAnnotation.getDeclaredAnnotations().length);
Assert.assertEquals(syntheticMetaAnnotation.getDeclaredAnnotations()[0], rootAnnotation); Assert.assertEquals(syntheticMetaAnnotation.getDeclaredAnnotations()[0], rootAnnotation);
Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotations().length); Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotations().length);
@ -59,35 +64,55 @@ public class SyntheticMetaAnnotationTest {
Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValueAlias", String.class)); Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValueAlias", String.class));
Assert.assertEquals("Child's Parent!", syntheticMetaAnnotation.getAttribute("parentValue", String.class)); Assert.assertEquals("Child's Parent!", syntheticMetaAnnotation.getAttribute("parentValue", String.class));
Assert.assertEquals("Child's GrandParent!", syntheticMetaAnnotation.getAttribute("grandParentValue", String.class)); Assert.assertEquals("Child's GrandParent!", syntheticMetaAnnotation.getAttribute("grandParentValue", String.class));
}
final ChildAnnotation childAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ChildAnnotation.class); @Test
public void syntheticAnnotationTest() {
final ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
SynthesizedMetaAnnotationAggregator syntheticMetaAnnotation = new SynthesizedMetaAnnotationAggregator(rootAnnotation);
final ChildAnnotation childAnnotation = syntheticMetaAnnotation.synthesize(ChildAnnotation.class);
SynthesizedAnnotation childSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(ChildAnnotation.class);
Assert.assertNotNull(childSyntheticAnnotation);
Assert.assertTrue(childSyntheticAnnotation.hasAttribute("childValue", String.class));
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), childSyntheticAnnotation.getRoot());
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), childSyntheticAnnotation.getAnnotation());
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class)); Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
Assert.assertNotNull(childAnnotation); Assert.assertNotNull(childAnnotation);
Assert.assertEquals("Child!", childAnnotation.childValue()); Assert.assertEquals("Child!", childAnnotation.childValue());
Assert.assertEquals("Child!", childAnnotation.childValueAlias()); Assert.assertEquals("Child!", childAnnotation.childValueAlias());
Assert.assertEquals(childAnnotation.grandParentType(), Integer.class); Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(childAnnotation)); Assert.assertThrows(IllegalArgumentException.class, () -> new SynthesizedMetaAnnotationAggregator(childAnnotation));
final ParentAnnotation parentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ParentAnnotation.class); final ParentAnnotation parentAnnotation = syntheticMetaAnnotation.synthesize(ParentAnnotation.class);
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class)); SynthesizedAnnotation parentSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(ParentAnnotation.class);
Assert.assertNotNull(parentSyntheticAnnotation);
Assert.assertTrue(parentSyntheticAnnotation.hasAttribute("parentValue", String.class));
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), parentSyntheticAnnotation.getRoot());
Assert.assertEquals(ChildAnnotation.class.getAnnotation(ParentAnnotation.class), parentSyntheticAnnotation.getAnnotation());
Assert.assertNotNull(parentAnnotation); Assert.assertNotNull(parentAnnotation);
Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue()); Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType()); Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(parentAnnotation)); Assert.assertThrows(IllegalArgumentException.class, () -> new SynthesizedMetaAnnotationAggregator(parentAnnotation));
final GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(GrandParentAnnotation.class); final GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.synthesize(GrandParentAnnotation.class);
SynthesizedAnnotation grandParentSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(GrandParentAnnotation.class);
Assert.assertNotNull(grandParentSyntheticAnnotation);
Assert.assertTrue(grandParentSyntheticAnnotation.hasAttribute("grandParentType", Class.class));
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), grandParentSyntheticAnnotation.getRoot());
Assert.assertEquals(ChildAnnotation.class.getAnnotation(GrandParentAnnotation.class), grandParentSyntheticAnnotation.getAnnotation());
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class)); Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
Assert.assertNotNull(grandParentAnnotation); Assert.assertNotNull(grandParentAnnotation);
Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue()); Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class); Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(grandParentAnnotation)); Assert.assertThrows(IllegalArgumentException.class, () -> new SynthesizedMetaAnnotationAggregator(grandParentAnnotation));
} }
@Test @Test
public void linkTest() { public void linkTest() {
final Method method = ReflectUtil.getMethod(AnnotationForLinkTest.class, "value"); final Method method = ReflectUtil.getMethod(AnnotationForLinkTest.class, "value");
final SyntheticAnnotation syntheticAnnotation = new SyntheticMetaAnnotation(method.getAnnotation(AliasFor.class)); final SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new SynthesizedMetaAnnotationAggregator(method.getAnnotation(AliasFor.class));
final Link link = syntheticAnnotation.syntheticAnnotation(Link.class); final Link link = synthesizedAnnotationAggregator.synthesize(Link.class);
Assert.assertEquals(AnnotationForLinkTest.class, link.annotation()); Assert.assertEquals(AnnotationForLinkTest.class, link.annotation());
Assert.assertEquals("name", link.attribute()); Assert.assertEquals("name", link.attribute());
} }
@ -95,20 +120,20 @@ public class SyntheticMetaAnnotationTest {
@Test @Test
public void mirrorAttributeTest() { public void mirrorAttributeTest() {
AnnotationForMirrorTest annotation = ClassForMirrorTest.class.getAnnotation(AnnotationForMirrorTest.class); AnnotationForMirrorTest annotation = ClassForMirrorTest.class.getAnnotation(AnnotationForMirrorTest.class);
SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
AnnotationForMirrorTest syntheticAnnotation = synthetic.syntheticAnnotation(AnnotationForMirrorTest.class); AnnotationForMirrorTest syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
Assert.assertEquals("Foo", syntheticAnnotation.name()); Assert.assertEquals("Foo", syntheticAnnotation.name());
Assert.assertEquals("Foo", syntheticAnnotation.value()); Assert.assertEquals("Foo", syntheticAnnotation.value());
annotation = ClassForMirrorTest2.class.getAnnotation(AnnotationForMirrorTest.class); annotation = ClassForMirrorTest2.class.getAnnotation(AnnotationForMirrorTest.class);
synthetic = new SyntheticMetaAnnotation(annotation); synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
syntheticAnnotation = synthetic.syntheticAnnotation(AnnotationForMirrorTest.class); syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
Assert.assertEquals("Foo", syntheticAnnotation.name()); Assert.assertEquals("Foo", syntheticAnnotation.name());
Assert.assertEquals("Foo", syntheticAnnotation.value()); Assert.assertEquals("Foo", syntheticAnnotation.value());
annotation = ClassForMirrorTest3.class.getAnnotation(AnnotationForMirrorTest.class); annotation = ClassForMirrorTest3.class.getAnnotation(AnnotationForMirrorTest.class);
synthetic = new SyntheticMetaAnnotation(annotation); synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
syntheticAnnotation = synthetic.syntheticAnnotation(AnnotationForMirrorTest.class); syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
AnnotationForMirrorTest finalSyntheticAnnotation = syntheticAnnotation; AnnotationForMirrorTest finalSyntheticAnnotation = syntheticAnnotation;
Assert.assertThrows(IllegalArgumentException.class, finalSyntheticAnnotation::name); Assert.assertThrows(IllegalArgumentException.class, finalSyntheticAnnotation::name);
} }
@ -116,71 +141,71 @@ public class SyntheticMetaAnnotationTest {
@Test @Test
public void aliasForTest() { public void aliasForTest() {
AnnotationForAliasForTest annotation = ClassForAliasForTest.class.getAnnotation(AnnotationForAliasForTest.class); AnnotationForAliasForTest annotation = ClassForAliasForTest.class.getAnnotation(AnnotationForAliasForTest.class);
SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
MetaAnnotationForAliasForTest metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForAliasForTest.class); MetaAnnotationForAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForAliasForTest.class);
Assert.assertEquals("Meta", metaAnnotation.name()); Assert.assertEquals("Meta", metaAnnotation.name());
AnnotationForAliasForTest childAnnotation = synthetic.syntheticAnnotation(AnnotationForAliasForTest.class); AnnotationForAliasForTest childAnnotation = synthetic.synthesize(AnnotationForAliasForTest.class);
Assert.assertEquals("", childAnnotation.value()); Assert.assertEquals("", childAnnotation.value());
annotation = ClassForAliasForTest2.class.getAnnotation(AnnotationForAliasForTest.class); annotation = ClassForAliasForTest2.class.getAnnotation(AnnotationForAliasForTest.class);
synthetic = new SyntheticMetaAnnotation(annotation); synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForAliasForTest.class); metaAnnotation = synthetic.synthesize(MetaAnnotationForAliasForTest.class);
Assert.assertEquals("Foo", metaAnnotation.name()); Assert.assertEquals("Foo", metaAnnotation.name());
childAnnotation = synthetic.syntheticAnnotation(AnnotationForAliasForTest.class); childAnnotation = synthetic.synthesize(AnnotationForAliasForTest.class);
Assert.assertEquals("Foo", childAnnotation.value()); Assert.assertEquals("Foo", childAnnotation.value());
} }
@Test @Test
public void forceAliasForTest() { public void forceAliasForTest() {
AnnotationForceForAliasForTest annotation = ClassForForceAliasForTest.class.getAnnotation(AnnotationForceForAliasForTest.class); AnnotationForceForAliasForTest annotation = ClassForForceAliasForTest.class.getAnnotation(AnnotationForceForAliasForTest.class);
SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
MetaAnnotationForForceAliasForTest metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForForceAliasForTest.class); MetaAnnotationForForceAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForForceAliasForTest.class);
Assert.assertEquals("", metaAnnotation.name()); Assert.assertEquals("", metaAnnotation.name());
AnnotationForceForAliasForTest childAnnotation = synthetic.syntheticAnnotation(AnnotationForceForAliasForTest.class); AnnotationForceForAliasForTest childAnnotation = synthetic.synthesize(AnnotationForceForAliasForTest.class);
Assert.assertEquals("", childAnnotation.value()); Assert.assertEquals("", childAnnotation.value());
annotation = ClassForForceAliasForTest2.class.getAnnotation(AnnotationForceForAliasForTest.class); annotation = ClassForForceAliasForTest2.class.getAnnotation(AnnotationForceForAliasForTest.class);
synthetic = new SyntheticMetaAnnotation(annotation); synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForForceAliasForTest.class); metaAnnotation = synthetic.synthesize(MetaAnnotationForForceAliasForTest.class);
Assert.assertEquals("Foo", metaAnnotation.name()); Assert.assertEquals("Foo", metaAnnotation.name());
childAnnotation = synthetic.syntheticAnnotation(AnnotationForceForAliasForTest.class); childAnnotation = synthetic.synthesize(AnnotationForceForAliasForTest.class);
Assert.assertEquals("Foo", childAnnotation.value()); Assert.assertEquals("Foo", childAnnotation.value());
} }
@Test @Test
public void aliasForAndMirrorTest() { public void aliasForAndMirrorTest() {
AnnotationForMirrorThenAliasForTest annotation = ClassForAliasForAndMirrorTest.class.getAnnotation(AnnotationForMirrorThenAliasForTest.class); AnnotationForMirrorThenAliasForTest annotation = ClassForAliasForAndMirrorTest.class.getAnnotation(AnnotationForMirrorThenAliasForTest.class);
SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
MetaAnnotationForMirrorThenAliasForTest metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForMirrorThenAliasForTest.class); MetaAnnotationForMirrorThenAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForMirrorThenAliasForTest.class);
Assert.assertEquals("test", metaAnnotation.name()); Assert.assertEquals("test", metaAnnotation.name());
Assert.assertEquals("test", metaAnnotation.value()); Assert.assertEquals("test", metaAnnotation.value());
AnnotationForMirrorThenAliasForTest childAnnotation = synthetic.syntheticAnnotation(AnnotationForMirrorThenAliasForTest.class); AnnotationForMirrorThenAliasForTest childAnnotation = synthetic.synthesize(AnnotationForMirrorThenAliasForTest.class);
Assert.assertEquals("test", childAnnotation.childValue()); Assert.assertEquals("test", childAnnotation.childValue());
} }
@Test @Test
public void multiAliasForTest() { public void multiAliasForTest() {
final AnnotationForMultiAliasForTest annotation = ClassForMultiAliasForTest.class.getAnnotation(AnnotationForMultiAliasForTest.class); final AnnotationForMultiAliasForTest annotation = ClassForMultiAliasForTest.class.getAnnotation(AnnotationForMultiAliasForTest.class);
final SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); final SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
final MetaAnnotationForMultiAliasForTest1 metaAnnotation1 = synthetic.syntheticAnnotation(MetaAnnotationForMultiAliasForTest1.class); final MetaAnnotationForMultiAliasForTest1 metaAnnotation1 = synthetic.synthesize(MetaAnnotationForMultiAliasForTest1.class);
Assert.assertEquals("test", metaAnnotation1.name()); Assert.assertEquals("test", metaAnnotation1.name());
Assert.assertEquals("test", metaAnnotation1.value1()); Assert.assertEquals("test", metaAnnotation1.value1());
final MetaAnnotationForMultiAliasForTest2 metaAnnotation2 = synthetic.syntheticAnnotation(MetaAnnotationForMultiAliasForTest2.class); final MetaAnnotationForMultiAliasForTest2 metaAnnotation2 = synthetic.synthesize(MetaAnnotationForMultiAliasForTest2.class);
Assert.assertEquals("test", metaAnnotation2.value2()); Assert.assertEquals("test", metaAnnotation2.value2());
final AnnotationForMultiAliasForTest childAnnotation = synthetic.syntheticAnnotation(AnnotationForMultiAliasForTest.class); final AnnotationForMultiAliasForTest childAnnotation = synthetic.synthesize(AnnotationForMultiAliasForTest.class);
Assert.assertEquals("test", childAnnotation.value3()); Assert.assertEquals("test", childAnnotation.value3());
} }
@Test @Test
public void implicitAliasTest() { public void implicitAliasTest() {
final AnnotationForImplicitAliasTest annotation = ClassForImplicitAliasTest.class.getAnnotation(AnnotationForImplicitAliasTest.class); final AnnotationForImplicitAliasTest annotation = ClassForImplicitAliasTest.class.getAnnotation(AnnotationForImplicitAliasTest.class);
final SyntheticAnnotation synthetic = new SyntheticMetaAnnotation(annotation); final SynthesizedAnnotationAggregator synthetic = new SynthesizedMetaAnnotationAggregator(annotation);
final MetaAnnotationForImplicitAliasTest metaAnnotation = synthetic.syntheticAnnotation(MetaAnnotationForImplicitAliasTest.class); final MetaAnnotationForImplicitAliasTest metaAnnotation = synthetic.synthesize(MetaAnnotationForImplicitAliasTest.class);
Assert.assertEquals("Meta", metaAnnotation.name()); Assert.assertEquals("Meta", metaAnnotation.name());
Assert.assertEquals("Foo", metaAnnotation.value()); Assert.assertEquals("Foo", metaAnnotation.value());
final AnnotationForImplicitAliasTest childAnnotation = synthetic.syntheticAnnotation(AnnotationForImplicitAliasTest.class); final AnnotationForImplicitAliasTest childAnnotation = synthetic.synthesize(AnnotationForImplicitAliasTest.class);
Assert.assertEquals("Foo", childAnnotation.value()); Assert.assertEquals("Foo", childAnnotation.value());
} }