diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractLinkAnnotationPostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractLinkAnnotationPostProcessor.java new file mode 100644 index 000000000..4c781101f --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractLinkAnnotationPostProcessor.java @@ -0,0 +1,160 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +/** + * {@link SynthesizedAnnotationPostProcessor}的基本实现, + * 用于处理注解中带有{@link Link}注解的属性。 + * + * @author huangchengxing + * @see MirrorLinkAnnotationPostProcessor + * @see AliasLinkAnnotationPostProcessor + */ +public abstract class AbstractLinkAnnotationPostProcessor implements SynthesizedAnnotationPostProcessor { + + /** + * 若一个注解属性上存在{@link Link}注解,注解的{@link Link#type()}返回值在{@link #processTypes()}中存在, + * 且此{@link Link}指定的注解对象在当前的{@link SynthesizedAnnotationAggregator}中存在, + * 则从聚合器中获取类型对应的合成注解对象,与该对象中的指定属性,然后将全部关联数据交给 + * {@link #processLinkedAttribute}处理。 + * + * @param synthesizedAnnotation 合成的注解 + * @param aggregator 合成注解聚合器 + */ + @Override + public void process(SynthesizedAnnotation synthesizedAnnotation, SynthesizedAnnotationAggregator aggregator) { + final Map attributeMap = new HashMap<>(synthesizedAnnotation.getAttributes()); + attributeMap.forEach((originalAttributeName, originalAttribute) -> { + // 获取注解 + final Link link = getLinkAnnotation(originalAttribute, processTypes()); + if (ObjectUtil.isNull(link)) { + return; + } + // 获取注解属性 + final SynthesizedAnnotation linkedAnnotation = getLinkedAnnotation(link, aggregator, synthesizedAnnotation.annotationType()); + if (ObjectUtil.isNull(linkedAnnotation)) { + return; + } + final AnnotationAttribute linkedAttribute = linkedAnnotation.getAttributes().get(link.attribute()); + // 处理 + processLinkedAttribute(aggregator, link, synthesizedAnnotation, originalAttribute, + linkedAnnotation, linkedAttribute + ); + }); + } + + // =========================== 抽象方法 =========================== + + /** + * 当属性上存在{@link Link}注解时,仅当{@link Link#type()}在本方法返回值内存在时才进行处理 + * + * @return 支持处理的{@link RelationType}类型 + */ + protected abstract RelationType[] processTypes(); + + /** + * 对关联的合成注解对象及其关联属性的处理 + * + * @param aggregator 合成注解聚合器 + * @param annotation {@code originalAttribute}上的{@link Link}注解对象 + * @param originalAnnotation 当前正在处理的{@link SynthesizedAnnotation}对象 + * @param originalAttribute {@code originalAnnotation}上的待处理的属性 + * @param linkedAnnotation {@link Link}指向的关联注解对象 + * @param linkedAttribute {@link Link}指向的{@code originalAnnotation}中的关联属性,该参数可能为空 + */ + protected abstract void processLinkedAttribute( + SynthesizedAnnotationAggregator aggregator, Link annotation, + SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute, + SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute + ); + + // =========================== @Link注解的处理 =========================== + + /** + * 从注解属性上获取指定类型的{@link Link}注解 + * + * @param attribute 注解属性 + * @param relationTypes 类型 + * @return 注解 + */ + protected Link getLinkAnnotation(AnnotationAttribute attribute, RelationType... relationTypes) { + return Opt.ofNullable(attribute) + .map(t -> AnnotationUtil.getSynthesizedAnnotation(attribute.getAttribute(), Link.class)) + .filter(a -> ArrayUtil.contains(relationTypes, a.type())) + .get(); + } + + /** + * 从合成注解中获取{@link Link#type()}指定的注解对象 + * + * @param annotation {@link Link}注解 + * @param synthesizedAnnotationAggregator 合成注解 + */ + protected SynthesizedAnnotation getLinkedAnnotation( + Link annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, Class defaultType) { + final Class targetAnnotationType = getLinkedAnnotationType(annotation, defaultType); + return synthesizedAnnotationAggregator.getSynthesizedAnnotation(targetAnnotationType); + } + + /** + * 若{@link Link#annotation()}获取的类型{@link Annotation#getClass()},则返回{@code defaultType}, + * 否则返回{@link Link#annotation()}指定的类型 + * + * @param annotation {@link Link}注解 + * @param defaultType 默认注解类型 + * @return 注解类型 + */ + protected Class getLinkedAnnotationType(Link annotation, Class defaultType) { + return ObjectUtil.equals(annotation.annotation(), Annotation.class) ? + defaultType : annotation.annotation(); + } + + // =========================== 注解属性的校验 =========================== + + /** + * 校验两个注解属性的返回值类型是否一致 + * + * @param original 原属性 + * @param alias 别名属性 + */ + protected void checkAttributeType(AnnotationAttribute original, AnnotationAttribute alias) { + Assert.equals( + original.getAttributeType(), alias.getAttributeType(), + "return type of the linked attribute [{}] is inconsistent with the original [{}]", + original.getAttribute(), alias.getAttribute() + ); + } + + /** + * 检查{@link Link}指向的注解属性是否就是本身 + * + * @param original {@link Link}注解的属性 + * @param linked {@link Link}指向的注解属性 + */ + protected 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}指向的注解属性是否存在 + * + * @param original {@link Link}注解的属性 + * @param linkedAttribute {@link Link}指向的注解属性 + * @param annotation {@link Link}注解 + */ + protected void checkLinkedAttributeNotNull(AnnotationAttribute original, AnnotationAttribute linkedAttribute, Link annotation) { + Assert.notNull(linkedAttribute, "cannot find linked attribute [{}] of original [{}] in [{}]", + original.getAttribute(), annotation.attribute(), + getLinkedAnnotationType(annotation, original.getAnnotationType()) + ); + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractSynthesizedAnnotation.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractSynthesizedAnnotation.java new file mode 100644 index 000000000..bf33bfadb --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractSynthesizedAnnotation.java @@ -0,0 +1,195 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.lang.Opt; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ObjectUtil; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * {@link SynthesizedAnnotation}的基本实现 + * + * @param 根对象类型 + * @author huangchengxing + */ +public abstract class AbstractSynthesizedAnnotation implements Annotation, SynthesizedAnnotation { + + private final SynthesizedAnnotationAggregator owner; + private final R root; + private final Annotation annotation; + private final Map attributeMethodCaches; + private final int verticalDistance; + private final int horizontalDistance; + + /** + * 创建一个合成注解 + * + * @param owner 合成注解所属的合成注解聚合器 + * @param root 根对象 + * @param annotation 被合成的注解对象 + * @param verticalDistance 距离根对象的水平距离 + * @param horizontalDistance 距离根对象的垂直距离 + */ + protected AbstractSynthesizedAnnotation( + SynthesizedAnnotationAggregator owner, R root, Annotation annotation, int verticalDistance, int horizontalDistance) { + this.owner = owner; + this.root = root; + this.annotation = annotation; + this.verticalDistance = verticalDistance; + this.horizontalDistance = horizontalDistance; + this.attributeMethodCaches = new HashMap<>(); + this.attributeMethodCaches.putAll(loadAttributeMethods()); + } + + /** + * 加载注解属性 + * + * @return 注解属性 + */ + protected Map loadAttributeMethods() { + return Stream.of(annotation.annotationType().getDeclaredMethods()) + .filter(AnnotationUtil::isAttributeMethod) + .collect(Collectors.toMap(Method::getName, method -> new CacheableAnnotationAttribute(annotation, method))); + } + + /** + * 元注解是否存在该属性 + * + * @param attributeName 属性名 + * @return 是否存在该属性 + */ + public boolean hasAttribute(String attributeName) { + return attributeMethodCaches.containsKey(attributeName); + } + + /** + * 元注解是否存在该属性,且该属性的值类型是指定类型或其子类 + * + * @param attributeName 属性名 + * @param returnType 返回值类型 + * @return 是否存在该属性 + */ + @Override + public boolean hasAttribute(String attributeName, Class returnType) { + return Opt.ofNullable(attributeMethodCaches.get(attributeName)) + .filter(method -> ClassUtil.isAssignable(returnType, method.getAttributeType())) + .isPresent(); + } + + /** + * 获取该注解的全部属性 + * + * @return 注解属性 + */ + @Override + public Map getAttributes() { + return this.attributeMethodCaches; + } + + /** + * 设置属性值 + * + * @param attributeName 属性名称 + * @param attribute 注解属性 + */ + @Override + public void setAttribute(String attributeName, AnnotationAttribute attribute) { + attributeMethodCaches.put(attributeName, attribute); + } + + /** + * 替换属性值 + * + * @param attributeName 属性名 + * @param operator 替换操作 + */ + @Override + public void replaceAttribute(String attributeName, UnaryOperator operator) { + AnnotationAttribute old = attributeMethodCaches.get(attributeName); + if (ObjectUtil.isNotNull(old)) { + attributeMethodCaches.put(attributeName, operator.apply(old)); + } + } + + /** + * 获取属性值 + * + * @param attributeName 属性名 + * @return 属性值 + */ + @Override + public Object getAttributeValue(String attributeName) { + return Opt.ofNullable(attributeMethodCaches.get(attributeName)) + .map(AnnotationAttribute::getValue) + .get(); + } + + /** + * 获取所属的合成注解集合器 + * + * @return 合成注解 + */ + @Override + public SynthesizedAnnotationAggregator getOwner() { + return owner; + } + + /** + * 获取该合成注解对应的根节点 + * + * @return 合成注解对应的根节点 + */ + @Override + public R getRoot() { + return root; + } + + /** + * 获取被合成的注解对象 + * + * @return 注解对象 + */ + @Override + public Annotation getAnnotation() { + return annotation; + } + + /** + * 获取该合成注解与根对象的垂直距离。 + * 默认情况下,该距离即为当前注解与根对象之间相隔的层级数。 + * + * @return 合成注解与根对象的垂直距离 + */ + @Override + public int getVerticalDistance() { + return verticalDistance; + } + + /** + * 获取该合成注解与根对象的水平距离。 + * 默认情况下,该距离即为当前注解与根对象之间相隔的已经被扫描到的注解数。 + * + * @return 合成注解与根对象的水平距离 + */ + @Override + public int getHorizontalDistance() { + return horizontalDistance; + } + + /** + * 获取被合成的注解类型 + * + * @return 被合成的注解类型 + */ + @Override + public Class annotationType() { + return annotation.annotationType(); + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasAttributePostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasAnnotationPostProcessor.java similarity index 75% rename from hutool-core/src/main/java/cn/hutool/core/annotation/AliasAttributePostProcessor.java rename to hutool-core/src/main/java/cn/hutool/core/annotation/AliasAnnotationPostProcessor.java index 3c0c2f0cf..a06578a6f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasAttributePostProcessor.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasAnnotationPostProcessor.java @@ -11,13 +11,15 @@ import cn.hutool.core.util.ObjectUtil; import java.util.Map; /** - * 用于处理合成注解属性中{@link Alias}的映射关系, - * 该处理器会令{@link Alias#value()}指向的属性值强制覆盖当前属性 + *

用于处理注解对象中带有{@link Alias}注解的属性。
+ * 当该处理器执行完毕后,{@link Alias}注解指向的目标注解的属性将会被包装并替换为 + * {@link ForceAliasedAnnotationAttribute}。 * * @author huangchengxing + * @see Alias * @see ForceAliasedAnnotationAttribute */ -public class AliasAttributePostProcessor implements SynthesizedAnnotationPostProcessor { +public class AliasAnnotationPostProcessor implements SynthesizedAnnotationPostProcessor { @Override public int order() { @@ -25,8 +27,8 @@ public class AliasAttributePostProcessor implements SynthesizedAnnotationPostPro } @Override - public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) { - final Map attributeMap = annotation.getAttributes(); + public void process(SynthesizedAnnotation synthesizedAnnotation, SynthesizedAnnotationAggregator aggregator) { + final Map attributeMap = synthesizedAnnotation.getAttributes(); // 记录别名与属性的关系 final ForestMap attributeAliasMappings = new LinkedForestMap<>(false); @@ -58,7 +60,7 @@ public class AliasAttributePostProcessor implements SynthesizedAnnotationPostPro attributeMap.put(attributeName, new ForceAliasedAnnotationAttribute(attribute, resolvedAttribute)); } }); - annotation.setAttributes(attributeMap); + synthesizedAnnotation.setAttributes(attributeMap); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessor.java deleted file mode 100644 index 4fbe48766..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessor.java +++ /dev/null @@ -1,106 +0,0 @@ -package cn.hutool.core.annotation; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.Opt; -import cn.hutool.core.util.ObjectUtil; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.BinaryOperator; - -/** - * 处理注解中带有{@link Link}注解,且{@link Link#type()}为{@link RelationType#FORCE_ALIAS_FOR} - * 或{@link RelationType#ALIAS_FOR}的属性。 - * - * @author huangchengxing - * @see ForceAliasedAnnotationAttribute - * @see AliasedAnnotationAttribute - */ -public class AliasForLinkAttributePostProcessor implements SynthesizedAnnotationPostProcessor { - - @Override - public int order() { - return Integer.MIN_VALUE + 2; - } - - @Override - public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) { - final Map attributeMap = new HashMap<>(annotation.getAttributes()); - attributeMap.forEach((originalAttributeName, originalAttribute) -> { - // 获取注解 - final Link link = SyntheticAnnotationUtil.getLink( - originalAttribute, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR - ); - if (ObjectUtil.isNull(link)) { - return; - } - - // 获取注解属性 - final SynthesizedAnnotation aliasAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, synthesizedAnnotationAggregator, annotation.annotationType()); - if (ObjectUtil.isNull(aliasAnnotation)) { - return; - } - final AnnotationAttribute aliasAttribute = aliasAnnotation.getAttributes().get(link.attribute()); - SyntheticAnnotationUtil.checkLinkedAttributeNotNull(originalAttribute, aliasAttribute, link); - SyntheticAnnotationUtil.checkAttributeType(originalAttribute, aliasAttribute); - checkCircularDependency(originalAttribute, aliasAttribute); - - // aliasFor - if (RelationType.ALIAS_FOR.equals(link.type())) { - wrappingLinkedAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, AliasedAnnotationAttribute::new); - return; - } - // forceAliasFor - wrappingLinkedAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, ForceAliasedAnnotationAttribute::new); - }); - } - - /** - * 对指定注解属性进行包装,若该属性已被包装过,则递归以其为根节点的树结构,对树上全部的叶子节点进行包装 - */ - private void wrappingLinkedAttribute( - SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute, AnnotationAttribute aliasAttribute, BinaryOperator wrapping) { - // 不是包装属性 - if (!aliasAttribute.isWrapped()) { - processAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, wrapping); - return; - } - // 是包装属性 - final AbstractWrappedAnnotationAttribute wrapper = (AbstractWrappedAnnotationAttribute)aliasAttribute; - wrapper.getAllLinkedNonWrappedAttributes().forEach( - t -> processAttribute(synthesizedAnnotationAggregator, originalAttribute, t, wrapping) - ); - } - - /** - * 获取指定注解属性,然后将其再进行一层包装 - */ - private void processAttribute( - SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute, - AnnotationAttribute target, BinaryOperator wrapping) { - Opt.ofNullable(target.getAnnotationType()) - .map(synthesizedAnnotationAggregator::getSynthesizedAnnotation) - .ifPresent(t -> t.replaceAttribute(target.getAttributeName(), old -> wrapping.apply(old, originalAttribute))); - } - - /** - * 检查两个属性是否互为别名 - */ - private void checkCircularDependency(AnnotationAttribute original, AnnotationAttribute alias) { - SyntheticAnnotationUtil.checkLinkedSelf(original, alias); - Link annotation = SyntheticAnnotationUtil.getLink(alias, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR); - if (ObjectUtil.isNull(annotation)) { - return; - } - final Class aliasAnnotationType = SyntheticAnnotationUtil.getLinkedAnnotationType(annotation, alias.getAnnotationType()); - if (ObjectUtil.notEqual(aliasAnnotationType, original.getAnnotationType())) { - return; - } - Assert.notEquals( - annotation.attribute(), original.getAttributeName(), - "circular reference between the alias attribute [{}] and the original attribute [{}]", - alias.getAttribute(), original.getAttribute() - ); - } - -} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessor.java new file mode 100644 index 000000000..5f3e26f5a --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessor.java @@ -0,0 +1,126 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.util.ObjectUtil; + +import java.util.function.BinaryOperator; + +/** + *

用于处理注解对象中带有{@link Link}注解,且{@link Link#type()}为 + * {@link RelationType#ALIAS_FOR}或{@link RelationType#FORCE_ALIAS_FOR}的属性。
+ * 当该处理器执行完毕后,{@link Link}注解指向的目标注解的属性将会被包装并替换为 + * {@link AliasedAnnotationAttribute}或{@link ForceAliasedAnnotationAttribute}。 + * + * @author huangchengxing + * @see RelationType#ALIAS_FOR + * @see AliasedAnnotationAttribute + * @see RelationType#FORCE_ALIAS_FOR + * @see ForceAliasedAnnotationAttribute + */ +public class AliasLinkAnnotationPostProcessor extends AbstractLinkAnnotationPostProcessor { + + private static final RelationType[] PROCESSED_RELATION_TYPES = new RelationType[]{ RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR }; + + @Override + public int order() { + return Integer.MIN_VALUE + 2; + } + + /** + * 该处理器只处理{@link Link#type()}类型为{@link RelationType#ALIAS_FOR}和{@link RelationType#FORCE_ALIAS_FOR}的注解属性 + * + * @return 含有{@link RelationType#ALIAS_FOR}和{@link RelationType#FORCE_ALIAS_FOR}的数组 + */ + @Override + protected RelationType[] processTypes() { + return PROCESSED_RELATION_TYPES; + } + + /** + * 获取{@link Link}指向的目标注解属性,并根据{@link Link#type()}的类型是 + * {@link RelationType#ALIAS_FOR}或{@link RelationType#FORCE_ALIAS_FOR} + * 将目标注解属性包装为{@link AliasedAnnotationAttribute}或{@link ForceAliasedAnnotationAttribute}, + * 然后用包装后注解属性在对应的合成注解中替换原始的目标注解属性 + * + * @param aggregator 合成注解聚合器 + * @param annotation {@code originalAttribute}上的{@link Link}注解对象 + * @param originalAnnotation 当前正在处理的{@link SynthesizedAnnotation}对象 + * @param originalAttribute {@code originalAnnotation}上的待处理的属性 + * @param linkedAnnotation {@link Link}指向的关联注解对象 + * @param linkedAttribute {@link Link}指向的{@code originalAnnotation}中的关联属性,该参数可能为空 + */ + @Override + protected void processLinkedAttribute( + SynthesizedAnnotationAggregator aggregator, Link annotation, + SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute, + SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute) { + // 校验别名关系 + checkAliasRelation(annotation, originalAttribute, linkedAttribute); + // 处理aliasFor类型的关系 + if (RelationType.ALIAS_FOR.equals(annotation.type())) { + wrappingLinkedAttribute(aggregator, originalAttribute, linkedAttribute, AliasedAnnotationAttribute::new); + return; + } + // 处理forceAliasFor类型的关系 + wrappingLinkedAttribute(aggregator, originalAttribute, linkedAttribute, ForceAliasedAnnotationAttribute::new); + } + + /** + * 对指定注解属性进行包装,若该属性已被包装过,则递归以其为根节点的树结构,对树上全部的叶子节点进行包装 + */ + private void wrappingLinkedAttribute( + SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute, AnnotationAttribute aliasAttribute, BinaryOperator wrapping) { + // 不是包装属性 + if (!aliasAttribute.isWrapped()) { + processAttribute(synthesizedAnnotationAggregator, originalAttribute, aliasAttribute, wrapping); + return; + } + // 是包装属性 + final AbstractWrappedAnnotationAttribute wrapper = (AbstractWrappedAnnotationAttribute)aliasAttribute; + wrapper.getAllLinkedNonWrappedAttributes().forEach( + t -> processAttribute(synthesizedAnnotationAggregator, originalAttribute, t, wrapping) + ); + } + + /** + * 获取指定注解属性,然后将其再进行一层包装 + */ + private void processAttribute( + SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, AnnotationAttribute originalAttribute, + AnnotationAttribute target, BinaryOperator wrapping) { + Opt.ofNullable(target.getAnnotationType()) + .map(synthesizedAnnotationAggregator::getSynthesizedAnnotation) + .ifPresent(t -> t.replaceAttribute(target.getAttributeName(), old -> wrapping.apply(old, originalAttribute))); + } + + /** + * 基本校验 + */ + private void checkAliasRelation(Link annotation, AnnotationAttribute originalAttribute, AnnotationAttribute linkedAttribute) { + checkLinkedAttributeNotNull(originalAttribute, linkedAttribute, annotation); + checkAttributeType(originalAttribute, linkedAttribute); + checkCircularDependency(originalAttribute, linkedAttribute); + } + + /** + * 检查两个属性是否互为别名 + */ + private void checkCircularDependency(AnnotationAttribute original, AnnotationAttribute alias) { + checkLinkedSelf(original, alias); + Link annotation = getLinkAnnotation(alias, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR); + if (ObjectUtil.isNull(annotation)) { + return; + } + final Class aliasAnnotationType = getLinkedAnnotationType(annotation, alias.getAnnotationType()); + if (ObjectUtil.notEqual(aliasAnnotationType, original.getAnnotationType())) { + return; + } + Assert.notEquals( + annotation.attribute(), original.getAttributeName(), + "circular reference between the alias attribute [{}] and the original attribute [{}]", + alias.getAttribute(), original.getAttribute() + ); + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasedAnnotationAttribute.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasedAnnotationAttribute.java index 53997f0ee..1c78d8175 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AliasedAnnotationAttribute.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AliasedAnnotationAttribute.java @@ -5,8 +5,7 @@ package cn.hutool.core.annotation; * 当别名属性值为默认值时,优先返回原属性的值,当别名属性不为默认值时,优先返回别名属性的值 * * @author huangchengxing - * @see AliasForLinkAttributePostProcessor - * @see RelationType#FORCE_ALIAS_FOR + * @see AliasLinkAnnotationPostProcessor * @see RelationType#ALIAS_FOR */ public class AliasedAnnotationAttribute extends AbstractWrappedAnnotationAttribute { diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java index 520d60a90..e4596446b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java @@ -40,7 +40,7 @@ public class CacheableSynthesizedAnnotationAttributeProcessor implements Synthes * 越靠前的越优先被取值。 */ public CacheableSynthesizedAnnotationAttributeProcessor() { - this(SyntheticAnnotationUtil.getChildPriorityAnnotationCompare()); + this(SynthesizedAnnotation.DEFAULT_CHILD_PRIORITY_COMPARATOR); } @SuppressWarnings("unchecked") diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/ForceAliasedAnnotationAttribute.java b/hutool-core/src/main/java/cn/hutool/core/annotation/ForceAliasedAnnotationAttribute.java index 6638bcbd2..312219c39 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/ForceAliasedAnnotationAttribute.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/ForceAliasedAnnotationAttribute.java @@ -5,8 +5,8 @@ package cn.hutool.core.annotation; * 当调用{@link #getValue()}时,总是返回{@link #linked}的值 * * @author huangchengxing - * @see AliasAttributePostProcessor - * @see AliasForLinkAttributePostProcessor + * @see AliasAnnotationPostProcessor + * @see AliasLinkAnnotationPostProcessor * @see RelationType#ALIAS_FOR * @see RelationType#FORCE_ALIAS_FOR */ diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessor.java new file mode 100644 index 000000000..e44b1889f --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessor.java @@ -0,0 +1,77 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; + +/** + *

用于处理注解对象中带有{@link Link}注解,且{@link Link#type()}为{@link RelationType#MIRROR_FOR}的属性。
+ * 当该处理器执行完毕后,原始合成注解中被{@link Link}注解的属性与{@link Link}注解指向的目标注解的属性, + * 都将会被被包装并替换为{@link MirroredAnnotationAttribute}。 + * + * @author huangchengxing + * @see RelationType#MIRROR_FOR + * @see MirroredAnnotationAttribute + */ +public class MirrorLinkAnnotationPostProcessor extends AbstractLinkAnnotationPostProcessor { + + private static final RelationType[] PROCESSED_RELATION_TYPES = new RelationType[]{ RelationType.MIRROR_FOR }; + + @Override + public int order() { + return Integer.MIN_VALUE + 1; + } + + /** + * 该处理器只处理{@link Link#type()}类型为{@link RelationType#MIRROR_FOR}的注解属性 + * + * @return 仅有{@link RelationType#MIRROR_FOR}数组 + */ + @Override + protected RelationType[] processTypes() { + return PROCESSED_RELATION_TYPES; + } + + /** + * 将存在镜像关系的合成注解属性分别包装为{@link MirroredAnnotationAttribute}对象, + * 并使用包装后{@link MirroredAnnotationAttribute}替换在它们对应合成注解实例中的{@link AnnotationAttribute} + * + * @param aggregator 合成注解聚合器 + * @param annotation {@code originalAttribute}上的{@link Link}注解对象 + * @param originalAnnotation 当前正在处理的{@link SynthesizedAnnotation}对象 + * @param originalAttribute {@code originalAnnotation}上的待处理的属性 + * @param linkedAnnotation {@link Link}指向的关联注解对象 + * @param linkedAttribute {@link Link}指向的{@code originalAnnotation}中的关联属性,该参数可能为空 + */ + @Override + protected void processLinkedAttribute( + SynthesizedAnnotationAggregator aggregator, Link annotation, + SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute, + SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute) { + // 校验镜像关系 + checkMirrorRelation(annotation, originalAttribute, linkedAttribute); + // 包装这一对镜像属性,并替换原注解中的对应属性 + final AnnotationAttribute mirroredOriginalAttribute = new MirroredAnnotationAttribute(originalAttribute, linkedAttribute); + originalAnnotation.setAttribute(originalAttribute.getAttributeName(), mirroredOriginalAttribute); + final AnnotationAttribute mirroredTargetAttribute = new MirroredAnnotationAttribute(linkedAttribute, originalAttribute); + linkedAnnotation.setAttribute(annotation.attribute(), mirroredTargetAttribute); + } + + /** + * 基本校验 + */ + private void checkMirrorRelation(Link annotation, AnnotationAttribute original, AnnotationAttribute mirror) { + // 镜像属性必须存在 + checkLinkedAttributeNotNull(original, mirror, annotation); + // 镜像属性返回值必须一致 + checkAttributeType(original, mirror); + // 镜像属性上必须存在对应的注解 + final Link mirrorAttributeAnnotation = getLinkAnnotation(mirror, RelationType.MIRROR_FOR); + Assert.isTrue( + ObjectUtil.isNotNull(mirrorAttributeAnnotation) && RelationType.MIRROR_FOR.equals(mirrorAttributeAnnotation.type()), + "mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]", + mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR + ); + checkLinkedSelf(original, mirror); + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessor.java deleted file mode 100644 index 8547b8a9b..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessor.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.hutool.core.annotation; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjectUtil; - -import java.util.HashMap; -import java.util.Map; - -/** - * 处理注解中带有{@link Link}注解,且{@link Link#type()}为{@link RelationType#MIRROR_FOR}的属性。 - * - * @author huangchengxing - * @see MirroredAnnotationAttribute - */ -public class MirrorLinkAttributePostProcessor implements SynthesizedAnnotationPostProcessor { - - @Override - public int order() { - return Integer.MIN_VALUE + 1; - } - - @Override - public void process(SynthesizedAnnotation annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator) { - Map attributeMap = new HashMap<>(annotation.getAttributes()); - attributeMap.forEach((originalAttributeName, originalAttribute) -> { - // 跳过已经解析的镜像属性 - if (originalAttribute instanceof MirroredAnnotationAttribute) { - return; - } - - // 获取注解 - final Link link = SyntheticAnnotationUtil.getLink(originalAttribute, RelationType.MIRROR_FOR); - if (ObjectUtil.isNull(link)) { - return; - } - - // 获取指定镜像属性所在的注解 - final SynthesizedAnnotation mirrorAnnotation = SyntheticAnnotationUtil.getLinkedAnnotation(link, synthesizedAnnotationAggregator, annotation.annotationType()); - if (ObjectUtil.isNull(mirrorAnnotation)) { - return; - } - - // 获取镜像属性,并进行校验 - final AnnotationAttribute mirrorAttribute = mirrorAnnotation.getAttributes().get(link.attribute()); - checkMirrorRelation(link, originalAttribute, mirrorAttribute); - - // 包装这一对镜像属性,并替换原注解中的对应属性 - final AnnotationAttribute mirroredOriginalAttribute = new MirroredAnnotationAttribute(originalAttribute, mirrorAttribute); - synthesizedAnnotationAggregator.getSynthesizedAnnotation(originalAttribute.getAnnotationType()) - .setAttribute(originalAttributeName, mirroredOriginalAttribute); - final AnnotationAttribute mirroredTargetAttribute = new MirroredAnnotationAttribute(mirrorAttribute, originalAttribute); - mirrorAnnotation.setAttribute(link.attribute(), mirroredTargetAttribute); - }); - } - - private void checkMirrorRelation(Link annotation, AnnotationAttribute original, AnnotationAttribute mirror) { - // 镜像属性必须存在 - SyntheticAnnotationUtil.checkLinkedAttributeNotNull(original, mirror, annotation); - // 镜像属性返回值必须一致 - SyntheticAnnotationUtil.checkAttributeType(original, mirror); - // 镜像属性上必须存在对应的注解 - final Link mirrorAttributeAnnotation = SyntheticAnnotationUtil.getLink(mirror, RelationType.MIRROR_FOR); - Assert.isTrue( - ObjectUtil.isNotNull(mirrorAttributeAnnotation) && RelationType.MIRROR_FOR.equals(mirrorAttributeAnnotation.type()), - "mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]", - mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR - ); - SyntheticAnnotationUtil.checkLinkedSelf(original, mirror); - } - -} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/MirroredAnnotationAttribute.java b/hutool-core/src/main/java/cn/hutool/core/annotation/MirroredAnnotationAttribute.java index e8f0f8efd..6bb800079 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/MirroredAnnotationAttribute.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/MirroredAnnotationAttribute.java @@ -6,7 +6,7 @@ import cn.hutool.core.lang.Assert; * 表示存在对应镜像属性的注解属性,当获取值时将根据{@link RelationType#MIRROR_FOR}的规则进行处理 * * @author huangchengxing - * @see MirrorLinkAttributePostProcessor + * @see MirrorLinkAnnotationPostProcessor * @see RelationType#MIRROR_FOR */ public class MirroredAnnotationAttribute extends AbstractWrappedAnnotationAttribute { diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotation.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotation.java index 2607d94f7..483525e2e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotation.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotation.java @@ -3,15 +3,15 @@ package cn.hutool.core.annotation; import cn.hutool.core.collection.CollUtil; import java.lang.annotation.Annotation; +import java.util.Comparator; import java.util.Map; import java.util.function.UnaryOperator; /** *

用于在{@link SynthesizedAnnotationAggregator}中表示一个处于合成状态的注解对象。
- * 当对多个合成注解排序时,默认先按{@link #getVerticalDistance()}排序, - * 再按{@link #getHorizontalDistance()}排序。 - * 该顺序应当保证当合成注解与其他注解存在层级关系时, - * 离根对象最接近的注解被排在靠前的位置。 + * 当对多个合成注解排序时,默认使用{@link #DEFAULT_CHILD_PRIORITY_COMPARATOR}进行排序, + * 从保证合成注解按{@link #getVerticalDistance()}与{@link #getHorizontalDistance()}的返回值保持有序, + * 从而使得距离根元素更接近的注解对象在被处理是具有更高的优先级。 * * @author huangchengxing * @see SynthesizedAnnotationAggregator @@ -19,7 +19,16 @@ import java.util.function.UnaryOperator; public interface SynthesizedAnnotation extends Annotation, Comparable { /** - * 获取所属的合成注解 + * {@link SynthesizedAnnotation}使用的默认的比较器, + * 按照按{@link #getVerticalDistance()}和{@link #getHorizontalDistance()}的返回值进行排序。
+ * 一般情况下,排序越小的合成注解应当被优先处理。 + */ + Comparator DEFAULT_CHILD_PRIORITY_COMPARATOR = Comparator + .comparing(SynthesizedAnnotation::getVerticalDistance) + .thenComparing(SynthesizedAnnotation::getHorizontalDistance); + + /** + * 获取所属的合成注解聚合器 * * @return 合成注解 */ @@ -114,7 +123,7 @@ public interface SynthesizedAnnotation extends Annotation, Comparable该接口存在多个实现类,调用者应当保证在任何时候,对一批后置处理器的调用顺序都符合: *

    - *
  • {@link AliasAttributePostProcessor};
  • - *
  • {@link MirrorLinkAttributePostProcessor};
  • - *
  • {@link AliasForLinkAttributePostProcessor};
  • + *
  • {@link AliasAnnotationPostProcessor};
  • + *
  • {@link MirrorLinkAnnotationPostProcessor};
  • + *
  • {@link AliasLinkAnnotationPostProcessor};
  • *
  • 其他后置处理器;
  • *
* * @author huangchengxing - * @see AliasAttributePostProcessor - * @see MirrorLinkAttributePostProcessor - * @see AliasForLinkAttributePostProcessor + * @see AliasAnnotationPostProcessor + * @see MirrorLinkAnnotationPostProcessor + * @see AliasLinkAnnotationPostProcessor */ public interface SynthesizedAnnotationPostProcessor extends Comparable { @@ -46,11 +46,11 @@ public interface SynthesizedAnnotationPostProcessor extends Comparable当扫描的注解对象经过{@link SynthesizedAnnotationSelector}处理后, - * 将会被转为{@link MetaAnnotation},并使用在实例化时指定的{@link AliasAttributePostProcessor} + * 将会被转为{@link MetaAnnotation},并使用在实例化时指定的{@link AliasAnnotationPostProcessor} * 进行后置处理。
* 默认情况下,将注册以下后置处理器以对{@link Alias}与{@link Link}和其扩展注解提供支持: *
    - *
  • {@link AliasAttributePostProcessor};
  • - *
  • {@link MirrorLinkAttributePostProcessor};
  • - *
  • {@link AliasForLinkAttributePostProcessor};
  • + *
  • {@link AliasAnnotationPostProcessor};
  • + *
  • {@link MirrorLinkAnnotationPostProcessor};
  • + *
  • {@link AliasLinkAnnotationPostProcessor};
  • *
* 若用户需要自行扩展,则需要保证上述三个处理器被正确注入当前实例。 * @@ -89,9 +84,9 @@ public class SynthesizedMetaAnnotationAggregator implements SynthesizedAnnotatio source, SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY, new CacheableSynthesizedAnnotationAttributeProcessor(), Arrays.asList( - new AliasAttributePostProcessor(), - new MirrorLinkAttributePostProcessor(), - new AliasForLinkAttributePostProcessor() + new AliasAnnotationPostProcessor(), + new MirrorLinkAnnotationPostProcessor(), + new AliasLinkAnnotationPostProcessor() ) ); } @@ -284,160 +279,23 @@ public class SynthesizedMetaAnnotationAggregator implements SynthesizedAnnotatio } /** - * 元注解包装类 + * 注解包装类,表示{@link #source}以及{@link #source}所属层级结构中的全部关联注解对象 * * @author huangchengxing */ - public static class MetaAnnotation implements Annotation, SynthesizedAnnotation { - - private final SynthesizedAnnotationAggregator owner; - private final Annotation root; - private final Annotation annotation; - private final Map attributeMethodCaches; - private final int verticalDistance; - private final int horizontalDistance; - - public MetaAnnotation(SynthesizedAnnotationAggregator owner, Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) { - this.owner = owner; - this.root = root; - this.annotation = annotation; - this.verticalDistance = verticalDistance; - this.horizontalDistance = horizontalDistance; - this.attributeMethodCaches = Stream.of(annotation.annotationType().getDeclaredMethods()) - .filter(AnnotationUtil::isAttributeMethod) - .collect(Collectors.toMap(Method::getName, method -> new CacheableAnnotationAttribute(annotation, method))); - } + public static class MetaAnnotation extends AbstractSynthesizedAnnotation { /** - * 获取所属的合成注解 + * 创建一个合成注解 * - * @return 合成注解 + * @param owner 合成注解所属的合成注解聚合器 + * @param root 根对象 + * @param annotation 被合成的注解对象 + * @param verticalDistance 距离根对象的水平距离 + * @param horizontalDistance 距离根对象的垂直距离 */ - @Override - public SynthesizedAnnotationAggregator getOwner() { - return owner; - } - - /** - * 获取注解类型 - * - * @return 注解类型 - */ - @Override - public Class annotationType() { - return annotation.annotationType(); - } - - /** - * 获取根注解 - * - * @return 根注解 - */ - @Override - public Annotation getRoot() { - return this.root; - } - - /** - * 获取元注解 - * - * @return 元注解 - */ - @Override - public Annotation getAnnotation() { - return annotation; - } - - /** - * 获取该合成注解与根注解之间相隔的层级数 - * - * @return 该合成注解与根注解之间相隔的层级数 - */ - @Override - public int getVerticalDistance() { - return verticalDistance; - } - - /** - * 获取该合成注解与根注解之间相隔的注解树 - * - * @return 该合成注解与根注解之间相隔的注解树 - */ - @Override - public int getHorizontalDistance() { - return horizontalDistance; - } - - /** - * 元注解是否存在该属性 - * - * @param attributeName 属性名 - * @return 是否存在该属性 - */ - public boolean hasAttribute(String attributeName) { - return attributeMethodCaches.containsKey(attributeName); - } - - /** - * 元注解是否存在该属性,且该属性的值类型是指定类型或其子类 - * - * @param attributeName 属性名 - * @param returnType 返回值类型 - * @return 是否存在该属性 - */ - @Override - public boolean hasAttribute(String attributeName, Class returnType) { - return Opt.ofNullable(attributeMethodCaches.get(attributeName)) - .filter(method -> ClassUtil.isAssignable(returnType, method.getAttributeType())) - .isPresent(); - } - - /** - * 获取该注解的全部属性 - * - * @return 注解属性 - */ - @Override - public Map getAttributes() { - return this.attributeMethodCaches; - } - - /** - * 设置属性值 - * - * @param attributeName 属性名称 - * @param attribute 注解属性 - */ - @Override - public void setAttribute(String attributeName, AnnotationAttribute attribute) { - attributeMethodCaches.put(attributeName, attribute); - } - - /** - * 替换属性值 - * - * @param attributeName 属性名 - * @param operator 替换操作 - */ - @Override - public void replaceAttribute(String attributeName, UnaryOperator operator) { - AnnotationAttribute old = attributeMethodCaches.get(attributeName); - if (ObjectUtil.isNotNull(old)) { - attributeMethodCaches.put(attributeName, operator.apply(old)); - } - } - - /** - * 获取属性值 - * - * @param attributeName 属性名 - * @return 属性值 - */ - @Override - public Object getAttributeValue(String attributeName) { - return Opt.ofNullable(attributeMethodCaches.get(attributeName)) - .map(AnnotationAttribute::getValue) - .get(); + protected MetaAnnotation(SynthesizedAnnotationAggregator owner, Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) { + super(owner, root, annotation, verticalDistance, horizontalDistance); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java index 5fb175cc5..f33557d7f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java @@ -80,7 +80,7 @@ class SyntheticAnnotationProxy implements InvocationHandler { void loadMethods() { methods.put("toString", (method, args) -> proxyToString()); methods.put("hashCode", (method, args) -> proxyHashCode()); - methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSyntheticAnnotation()); + methods.put("getSynthesizedAnnotationAggregator", (method, args) -> proxyGetSynthesizedAnnotationAggregator()); methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation()); methods.put("getRoot", (method, args) -> annotation.getRoot()); methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance()); @@ -110,7 +110,7 @@ class SyntheticAnnotationProxy implements InvocationHandler { return Objects.hash(annotation.getOwner(), annotation); } - private Object proxyGetSyntheticAnnotation() { + private Object proxyGetSynthesizedAnnotationAggregator() { return annotation.getOwner(); } @@ -134,7 +134,7 @@ class SyntheticAnnotationProxy implements InvocationHandler { * * @return 合成注解 */ - SynthesizedAnnotationAggregator getSyntheticAnnotation(); + SynthesizedAnnotationAggregator getSynthesizedAnnotationAggregator(); /** * 获取该代理注解对应的已合成注解 diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationUtil.java deleted file mode 100644 index 9a5f8f5a4..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationUtil.java +++ /dev/null @@ -1,106 +0,0 @@ -package cn.hutool.core.annotation; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.Opt; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjectUtil; - -import java.lang.annotation.Annotation; -import java.util.Comparator; - -/** - * {@link SynthesizedAnnotationAggregator}相关工具,用于内部使用 - * - * @author huangchengxing - */ -class SyntheticAnnotationUtil { - - /** - * 从注解属性上获取指定类型的{@link Link}注解 - * - * @param attribute 注解属性 - * @param relationTypes 类型 - * @return 注解 - */ - static Link getLink(AnnotationAttribute attribute, RelationType... relationTypes) { - return Opt.ofNullable(attribute) - .map(t -> AnnotationUtil.getSynthesizedAnnotation(attribute.getAttribute(), Link.class)) - .filter(a -> ArrayUtil.contains(relationTypes, a.type())) - .get(); - } - - /** - * 从合成注解中获取{@link Link#type()}指定的注解对象 - * - * @param annotation {@link Link}注解 - * @param synthesizedAnnotationAggregator 合成注解 - */ - static SynthesizedAnnotation getLinkedAnnotation( - Link annotation, SynthesizedAnnotationAggregator synthesizedAnnotationAggregator, Class defaultType) { - final Class targetAnnotationType = getLinkedAnnotationType(annotation, defaultType); - return synthesizedAnnotationAggregator.getSynthesizedAnnotation(targetAnnotationType); - } - - /** - * 若{@link Link#annotation()}获取的类型{@link Annotation#getClass()},则返回{@code defaultType}, - * 否则返回{@link Link#annotation()}指定的类型 - * - * @param annotation {@link Link}注解 - * @param defaultType 默认注解类型 - * @return 注解类型 - */ - static Class getLinkedAnnotationType(Link annotation, Class defaultType) { - return ObjectUtil.equals(annotation.annotation(), Annotation.class) ? - defaultType : annotation.annotation(); - } - - /** - * 校验两个注解属性的返回值类型是否一致 - * - * @param original 原属性 - * @param alias 别名属性 - */ - static void checkAttributeType(AnnotationAttribute original, AnnotationAttribute alias) { - Assert.equals( - original.getAttributeType(), alias.getAttributeType(), - "return type of the linked attribute [{}] is inconsistent with the original [{}]", - original.getAttribute(), alias.getAttribute() - ); - } - - /** - * 检查{@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}指向的注解属性是否存在 - * - * @param original {@link Link}注解的属性 - * @param linkedAttribute {@link Link}指向的注解属性 - * @param annotation {@link Link}注解 - */ - static void checkLinkedAttributeNotNull(AnnotationAttribute original, AnnotationAttribute linkedAttribute, Link annotation) { - Assert.notNull(linkedAttribute, "cannot find linked attribute [{}] of original [{}] in [{}]", - original.getAttribute(), annotation.attribute(), - getLinkedAnnotationType(annotation, original.getAnnotationType()) - ); - } - - /** - * 获取按{@link SynthesizedAnnotation#getVerticalDistance()}和{@link SynthesizedAnnotation#getHorizontalDistance()}排序的比较器 - * - * @return 比较值 - */ - static Comparator getChildPriorityAnnotationCompare() { - return Comparator.comparing(SynthesizedAnnotation::getVerticalDistance) - .thenComparing(SynthesizedAnnotation::getHorizontalDistance); - } - -} diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AliasAttributePostProcessorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AliasAnnotationPostProcessorTest.java similarity index 97% rename from hutool-core/src/test/java/cn/hutool/core/annotation/AliasAttributePostProcessorTest.java rename to hutool-core/src/test/java/cn/hutool/core/annotation/AliasAnnotationPostProcessorTest.java index f7ad67e8b..8c792a1c9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AliasAttributePostProcessorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AliasAnnotationPostProcessorTest.java @@ -12,11 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.function.UnaryOperator; -public class AliasAttributePostProcessorTest { +public class AliasAnnotationPostProcessorTest { @Test public void processTest() { - AliasAttributePostProcessor processor = new AliasAttributePostProcessor(); + AliasAnnotationPostProcessor processor = new AliasAnnotationPostProcessor(); Map, SynthesizedAnnotation> annotationMap = new HashMap<>(); SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessorTest.java similarity index 96% rename from hutool-core/src/test/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessorTest.java rename to hutool-core/src/test/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessorTest.java index 5d0c4ad37..339b012d5 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AliasForLinkAttributePostProcessorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AliasLinkAnnotationPostProcessorTest.java @@ -12,11 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.function.UnaryOperator; -public class AliasForLinkAttributePostProcessorTest { +public class AliasLinkAnnotationPostProcessorTest { @Test public void processForceAliasForTest() { - AliasForLinkAttributePostProcessor processor = new AliasForLinkAttributePostProcessor(); + AliasLinkAnnotationPostProcessor processor = new AliasLinkAnnotationPostProcessor(); Map, SynthesizedAnnotation> annotationMap = new HashMap<>(); SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap); @@ -40,7 +40,7 @@ public class AliasForLinkAttributePostProcessorTest { @Test public void processAliasForTest() { - AliasForLinkAttributePostProcessor processor = new AliasForLinkAttributePostProcessor(); + AliasLinkAnnotationPostProcessor processor = new AliasLinkAnnotationPostProcessor(); Map, SynthesizedAnnotation> annotationMap = new HashMap<>(); SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessorTest.java similarity index 97% rename from hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessorTest.java rename to hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessorTest.java index d6e8902db..2c741e32d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAttributePostProcessorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/MirrorLinkAnnotationPostProcessorTest.java @@ -12,11 +12,11 @@ import java.util.HashMap; import java.util.Map; import java.util.function.UnaryOperator; -public class MirrorLinkAttributePostProcessorTest { +public class MirrorLinkAnnotationPostProcessorTest { @Test public void processTest() { - MirrorLinkAttributePostProcessor processor = new MirrorLinkAttributePostProcessor(); + MirrorLinkAnnotationPostProcessor processor = new MirrorLinkAnnotationPostProcessor(); Map, SynthesizedAnnotation> annotationMap = new HashMap<>(); SynthesizedAnnotationAggregator synthesizedAnnotationAggregator = new TestSynthesizedAnnotationAggregator(annotationMap); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java index 0b3f31f81..c9eed2014 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/scanner/TypeAnnotationScannerTest.java @@ -36,7 +36,7 @@ public class TypeAnnotationScannerTest { annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); // 不查找父类 - scanner = new TypeAnnotationScanner().setIncludeSupperClass(false); + scanner = new TypeAnnotationScanner().setIncludeSuperClass(false); annotations = scanner.getAnnotations(Example.class); Assert.assertEquals(1, annotations.size()); annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class)); @@ -88,7 +88,7 @@ public class TypeAnnotationScannerTest { // 不查找父类 map.clear(); new TypeAnnotationScanner() - .setIncludeSupperClass(false) + .setIncludeSuperClass(false) .scan( (index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation), Example.class, null