mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
添加AnnotatedElementUtil工具类
This commit is contained in:
parent
4b38bc31d2
commit
6c6eeb49d7
@ -0,0 +1,615 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.map.WeakConcurrentMap;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>{@link AnnotatedElement}工具类,提供对层级结构中{@link AnnotatedElement}上注解及元注解的访问支持,
|
||||
* 并提供诸如基于{@link Alias}的属性别名、基于父子注解间的属性值覆盖等特殊的属性映射机制支持。
|
||||
*
|
||||
* <p><strong>搜索层级结构</strong>
|
||||
* <p>参考 Spring 中<code>AnnotatedElementUtils</code>,
|
||||
* 工具类提供<em>get</em>以及<em>find</em>两种语义的搜索:
|
||||
* <ul>
|
||||
* <li><em>get</em>:表示搜索范围仅限于指定的{@link AnnotatedElement}本身;</li>
|
||||
* <li>
|
||||
* <em>find</em>:表示搜索范围除了指定的{@link AnnotatedElement}本身外,
|
||||
* 若{@link AnnotatedElement}是类,则还会搜索其所有关联的父类和父接口;
|
||||
* 若{@link AnnotatedElement}是方法,则还会搜索其声明类关联的所有父类和父接口中,与该方法具有相同方法签名的方法对象;<br>
|
||||
* </li>
|
||||
* </ul>
|
||||
* eg: <br>
|
||||
* 若类<em>A</em>分别有父类和父接口<em>B</em>、<em>C</em>,
|
||||
* 则通过<em>getXXX</em>方法将只能获得<em>A</em>上的注解,
|
||||
* 而通过<em>getXXX</em>方法将能获得<em>A</em>、<em>B</em>、<em>C</em>上的注解。
|
||||
*
|
||||
* <p><strong>搜索元注解</strong>
|
||||
* <p>工具类支持搜索注解的元注解。在所有格式为<em>getXXX</em>或<em>findXXX</em>的静态方法中,
|
||||
* 若不带有<em>directly</em>关键字,则该方法支持搜索元注解,否则皆支持搜索元注解。<br>
|
||||
* eg: <br>
|
||||
* 若类<em>A</em>分别有父类和父接口<em>B</em>、<em>C</em>,上面分别有注解<em>X</em>与其元注解<em>Y</em>,
|
||||
* 则此时基于<em>A</em>有:
|
||||
* <ul>
|
||||
* <li><em>getDirectlyXXX</em>:能够获得<em>A</em>上的注解<em>X</em>;</li>
|
||||
* <li><em>getXXX</em>:能够获得<em>A</em>上的注解<em>X</em>及元注解<em>Y</em>;</li>
|
||||
* <li><em>findDirectlyXXX</em>:能够分别获得<em>A</em>、<em>B</em>、<em>C</em>上的注解<em>X</em>;</li>
|
||||
* <li><em>findXXX</em>:能够分别获得<em>A</em>、<em>B</em>、<em>C</em>上的注解<em>X</em>及元注解<em>Y</em>;</li>
|
||||
* </ul>
|
||||
* 注意:在当前实例中将无视{@link Inherited}的效果,即通过<em>directly</em>方法将无法获得父类上带有{@link Inherited}的注解。
|
||||
*
|
||||
* <p><strong>注解属性映射</strong>
|
||||
* <p>工具类支持注解对象属性上的一些属性映射机制,即当注解被扫描时,
|
||||
* 将根据一些属性映射机制“解析”为其他类型的属性,这里支持的机制包括:
|
||||
* <ul>
|
||||
* <li>
|
||||
* 基于{@link Alias}的属性别名:若注解属性通过{@link Alias}互相关联,则对其中任意属性赋值,则等同于对所有关联属性赋值;<br>
|
||||
* eg:
|
||||
* <pre><code>
|
||||
* // set aliased attributes
|
||||
* {@literal @}interface FooAnnotation {
|
||||
* {@literal @}Alias("alias")
|
||||
* default String value() default "";
|
||||
* {@literal @}Alias("value")
|
||||
* default String alias() default "";
|
||||
* }
|
||||
* {@literal @}FooAnnotation("foo")
|
||||
* class Foo { }
|
||||
*
|
||||
* // get resolved annotation
|
||||
* FooAnnotation annotation = getResolvedAnnotation(Foo.class, FooAnnotation.class);
|
||||
* annotation.value(); // = "foo"
|
||||
* annotation.alias(); // = "foo"
|
||||
* }</code></pre>
|
||||
* </li>
|
||||
* <li>
|
||||
* 基于父子注解的属性覆写:若子注解中存在属性,与其元注解的属性名称、类型皆相同,则子注解的属性值将会覆写其元注解的属性值,
|
||||
* 若被覆写的属性值存在关联别名,则关联别名也会被一并覆写。<br>
|
||||
* eg:
|
||||
* <pre><code>
|
||||
* {@literal @}interface Meta {
|
||||
* default String value() default "";
|
||||
* }
|
||||
* {@literal @}Meta("meta")
|
||||
* {@literal @}interface Root {
|
||||
* default String value() default ""; // overwrite for @Meta.value
|
||||
* }
|
||||
* {@literal @}Root("foo")
|
||||
* class Foo { }
|
||||
*
|
||||
* // get resolved annotation
|
||||
* Meta meta = getResolvedAnnotation(Foo.class, Meta.class);
|
||||
* meta.value(); // = "foo"
|
||||
* Root root = getResolvedAnnotation(Foo.class, Root.class);
|
||||
* root.value(); // = "foo"
|
||||
* </code></pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author huangchengxing
|
||||
* @see ResolvedAnnotationMapping
|
||||
* @see GenericAnnotationMapping
|
||||
* @see HierarchicalAnnotatedElements
|
||||
* @see MetaAnnotatedElement
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class AnnotatedElementUtil {
|
||||
|
||||
/**
|
||||
* 支持属性解析的{@link MetaAnnotatedElement}缓存
|
||||
*/
|
||||
private static final Map<AnnotatedElement, MetaAnnotatedElement<ResolvedAnnotationMapping>> RESOLVED_ELEMENT_CACHE = new WeakConcurrentMap<>();
|
||||
|
||||
/**
|
||||
* 不支持属性解析的{@link MetaAnnotatedElement}缓存
|
||||
*/
|
||||
private static final Map<AnnotatedElement, MetaAnnotatedElement<GenericAnnotationMapping>> ELEMENT_CACHE = new WeakConcurrentMap<>();
|
||||
|
||||
// region ========== find ==========
|
||||
|
||||
/**
|
||||
* 在{@code element}所处层级结构的所有{@link AnnotatedElement}上,是否存在该类型的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isAnnotated(final AnnotatedElement element, final Class<? extends Annotation> annotationType) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.isAnnotationPresent(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取该类型的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T findAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有该类型的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T[] findAllAnnotations(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getAnnotationsByType(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] findAnnotations(final AnnotatedElement element) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有的注解或元注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T findResolvedAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有的注解或元注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] findResolvedAnnotations(final AnnotatedElement element) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有该类型的注解或元注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T[] findAllResolvedAnnotations(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getAnnotationsByType(annotationType);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ========== find & direct ==========
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取该类型的注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T findDirectlyAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getDeclaredAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有该类型的注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T[] findAllDirectlyAnnotations(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getDeclaredAnnotationsByType(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有的注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] findDirectlyAnnotations(final AnnotatedElement element) {
|
||||
return toHierarchyMetaElement(element, false)
|
||||
.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有的注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T findDirectlyResolvedAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getDeclaredAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有的注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] findDirectlyResolvedAnnotations(final AnnotatedElement element) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有该类型的注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T[] findAllDirectlyResolvedAnnotations(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toHierarchyMetaElement(element, true)
|
||||
.getDeclaredAnnotationsByType(annotationType);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ========== get ==========
|
||||
|
||||
/**
|
||||
* 在{@code element}上,是否存在该类型的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isAnnotationPresent(final AnnotatedElement element, final Class<? extends Annotation> annotationType) {
|
||||
return toMetaElement(element, false)
|
||||
.isAnnotationPresent(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取该类型的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T getAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toMetaElement(element, false)
|
||||
.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取所有的注解或元注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] getAnnotations(final AnnotatedElement element) {
|
||||
return toMetaElement(element, false)
|
||||
.getAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取所有的注解或元注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T getResolvedAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toMetaElement(element, true)
|
||||
.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取所有的注解或元注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] getResolvedAnnotations(final AnnotatedElement element) {
|
||||
return toMetaElement(element, true)
|
||||
.getAnnotations();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ========== get & direct ==========
|
||||
|
||||
/**
|
||||
* 从{@code element}上获取该类型的注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T getDirectlyAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toMetaElement(element, false)
|
||||
.getDeclaredAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上获取所有的注解
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] getDirectlyAnnotations(final AnnotatedElement element) {
|
||||
return toMetaElement(element, false)
|
||||
.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取所有的注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @param annotationType 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static <T extends Annotation> T getDirectlyResolvedAnnotation(final AnnotatedElement element, final Class<T> annotationType) {
|
||||
return toMetaElement(element, true)
|
||||
.getDeclaredAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@code element}上,获取所有的注解。<br>
|
||||
* 得到的注解支持基于{@link Alias}的别名机制。
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return 注解对象
|
||||
*/
|
||||
public static Annotation[] getDirectlyResolvedAnnotations(final AnnotatedElement element) {
|
||||
return toMetaElement(element, true)
|
||||
.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ========== to element ==========
|
||||
|
||||
/**
|
||||
* <p>扫描{@code element}所处层级结构中的{@link AnnotatedElement},
|
||||
* 并将其全部转为{@link MetaAnnotatedElement}后,
|
||||
* 再把所有对象合并为{@link HierarchicalAnnotatedElements}。<br>
|
||||
* 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的注解及元注解。
|
||||
*
|
||||
* @param element 元素
|
||||
* @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
|
||||
* @return {@link HierarchicalAnnotatedElements}实例
|
||||
* @see #getMetaElementCache(AnnotatedElement)
|
||||
* @see #getResolvedMetaElementCache(AnnotatedElement)
|
||||
*/
|
||||
public static AnnotatedElement toHierarchyMetaElement(final AnnotatedElement element, final boolean resolved) {
|
||||
if (Objects.isNull(element)) {
|
||||
return emptyElement();
|
||||
}
|
||||
if (resolved) {
|
||||
return HierarchicalAnnotatedElements.create(element, (es, e) -> getResolvedMetaElementCache(e));
|
||||
}
|
||||
return HierarchicalAnnotatedElements.create(element, (es, e) -> getMetaElementCache(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>扫描{@code element}所处层级结构中的{@link AnnotatedElement},
|
||||
* 再把所有对象合并为{@link HierarchicalAnnotatedElements}
|
||||
* 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的注解。
|
||||
*
|
||||
* @param element 元素
|
||||
* @return {@link AnnotatedElement}实例
|
||||
*/
|
||||
public static AnnotatedElement toHierarchyElement(final AnnotatedElement element) {
|
||||
return ObjUtil.defaultIfNull(
|
||||
element, ele -> HierarchicalAnnotatedElements.create(ele, (es, e) -> e), emptyElement()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@link AnnotatedElement}转为{@link MetaAnnotatedElement},
|
||||
* 得到的对象可访问{@code element}上所有的注解及元注解。
|
||||
*
|
||||
* @param element 元素
|
||||
* @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制
|
||||
* @return {@link AnnotatedElement}实例
|
||||
* @see #getMetaElementCache(AnnotatedElement)
|
||||
* @see #getResolvedMetaElementCache(AnnotatedElement)
|
||||
*/
|
||||
public static AnnotatedElement toMetaElement(final AnnotatedElement element, final boolean resolved) {
|
||||
return ObjUtil.defaultIfNull(
|
||||
element, e -> resolved ? getResolvedMetaElementCache(e) : getMetaElementCache(e), emptyElement()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一组注解中的非{@code null}注解对象合并为一个{@link AnnotatedElement}
|
||||
*
|
||||
* @param annotations 注解
|
||||
* @return {@link AnnotatedElement}实例
|
||||
* @see ConstantElement
|
||||
*/
|
||||
public static AnnotatedElement asElement(Annotation... annotations) {
|
||||
annotations = ArrayUtil.filter(annotations, Objects::nonNull);
|
||||
return ArrayUtil.isEmpty(annotations) ?
|
||||
emptyElement() : new ConstantElement(annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个不包含任何注解的{@link AnnotatedElement}
|
||||
*
|
||||
* @return {@link AnnotatedElement}实例
|
||||
* @see EmptyElement
|
||||
*/
|
||||
public static AnnotatedElement emptyElement() {
|
||||
return EmptyElement.INSTANCE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ========== private ==========
|
||||
|
||||
/**
|
||||
* 创建一个支持注解解析的{@link MetaAnnotatedElement}
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return {@link MetaAnnotatedElement}实例
|
||||
*/
|
||||
private static MetaAnnotatedElement<ResolvedAnnotationMapping> getResolvedMetaElementCache(final AnnotatedElement element) {
|
||||
return RESOLVED_ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
|
||||
element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个支持注解解析的{@link MetaAnnotatedElement}
|
||||
*
|
||||
* @param element {@link AnnotatedElement}
|
||||
* @return {@link MetaAnnotatedElement}实例
|
||||
*/
|
||||
private static MetaAnnotatedElement<GenericAnnotationMapping> getMetaElementCache(final AnnotatedElement element) {
|
||||
return ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
|
||||
element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source))
|
||||
));
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 由一组注解聚合来的{@link AnnotatedElement}
|
||||
*/
|
||||
private static class ConstantElement implements AnnotatedElement {
|
||||
|
||||
/**
|
||||
* 注解对象
|
||||
*/
|
||||
private final Annotation[] annotations;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param annotations 注解
|
||||
*/
|
||||
ConstantElement(final Annotation[] annotations) {
|
||||
this.annotations = Objects.requireNonNull(annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的注解对象
|
||||
*
|
||||
* @param annotationClass 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return 注解
|
||||
*/
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
|
||||
return Stream.of(annotations)
|
||||
.filter(annotation -> Objects.equals(annotation.annotationType(), annotationClass))
|
||||
.findFirst()
|
||||
.map(annotationClass::cast)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定直接所有的注解对象
|
||||
*
|
||||
* @return 注解
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return annotations.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定直接声明的注解对象
|
||||
*
|
||||
* @return 注解
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return annotations.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不包含任何注解的{@link AnnotatedElement}
|
||||
*/
|
||||
private static class EmptyElement implements AnnotatedElement {
|
||||
|
||||
/**
|
||||
* 默认的空实例
|
||||
*/
|
||||
static final EmptyElement INSTANCE = new EmptyElement();
|
||||
|
||||
/**
|
||||
* 固定返回{@code null}
|
||||
*
|
||||
* @param annotationClass 注解类型
|
||||
* @param <T> 注解类型
|
||||
* @return {@code null}
|
||||
*/
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 固定返回空数组
|
||||
*
|
||||
* @return 空数组
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 固定返回空数组
|
||||
*
|
||||
* @return 空数组
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,480 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* test for {@link AnnotatedElementUtil}
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public class AnnotatedElementUtilTest {
|
||||
|
||||
private final static Annotation3 ANNOTATION3 = Foo.class.getAnnotation(Annotation3.class); // Foo.class's annotations
|
||||
private final static Annotation2 ANNOTATION2 = Annotation3.class.getAnnotation(Annotation2.class);
|
||||
private final static Annotation1 ANNOTATION1 = Annotation2.class.getAnnotation(Annotation1.class);
|
||||
|
||||
private final static Annotation4 ANNOTATION4 = Super.class.getAnnotation(Annotation4.class); // Super.class's annotations
|
||||
|
||||
private final static Annotation6 ANNOTATION6 = Interface.class.getAnnotation(Annotation6.class); // Interface.class's annotations
|
||||
private final static Annotation5 ANNOTATION5 = Annotation6.class.getAnnotation(Annotation5.class);
|
||||
|
||||
private final static Annotation[] DECLARED_ANNOTATIONS = new Annotation[]{
|
||||
ANNOTATION3, // Foo.class's annotations
|
||||
ANNOTATION4, // Super.class's annotations
|
||||
ANNOTATION6 // Interface.class's annotations
|
||||
};
|
||||
private final static Annotation[] ANNOTATIONS = new Annotation[]{
|
||||
ANNOTATION3, ANNOTATION2, ANNOTATION1, // Foo.class's annotations
|
||||
ANNOTATION4, // Super.class's annotations
|
||||
ANNOTATION6, ANNOTATION5 // Interface.class's annotations
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testIsAnnotated() {
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation1.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation2.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation3.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation4.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation5.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAnnotation() {
|
||||
Assert.assertEquals(ANNOTATION1, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertEquals(ANNOTATION2, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation3.class));
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllAnnotations() {
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION1}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation1.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION2}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation2.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION3}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation3.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION4}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation4.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION5}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation5.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION6}, AnnotatedElementUtil.findAllAnnotations(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAnnotations() {
|
||||
Annotation[] annotations = AnnotatedElementUtil.findAnnotations(Foo.class);
|
||||
Assert.assertArrayEquals(ANNOTATIONS, annotations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindResolvedAnnotation() {
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation6.class));
|
||||
Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findResolvedAnnotation(Foo.class, Annotation5.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindResolvedAnnotations() {
|
||||
Annotation[] resolvedAnnotations = AnnotatedElementUtil.findResolvedAnnotations(Foo.class);
|
||||
Map<Class<?>, Annotation> annotationMap = Stream.of(resolvedAnnotations).collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
|
||||
|
||||
Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = (Annotation2)annotationMap.get(Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = (Annotation1)annotationMap.get(Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, annotationMap.get(Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION6, annotationMap.get(Annotation6.class));
|
||||
Assert.assertEquals(ANNOTATION5, annotationMap.get(Annotation5.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllResolvedAnnotations() {
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation3.class)[0];
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation2.class)[0];
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation1.class)[0];
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation4.class)[0]);
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation6.class)[0]);
|
||||
Assert.assertEquals(ANNOTATION5, AnnotatedElementUtil.findAllResolvedAnnotations(Foo.class, Annotation5.class)[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindDirectlyAnnotation() {
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation3.class));
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findDirectlyAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllDirectlyAnnotations() {
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation1.class).length);
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation2.class).length);
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION3}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation3.class));
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION4}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation4.class));
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation5.class).length);
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION6}, AnnotatedElementUtil.findAllDirectlyAnnotations(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindDirectlyAnnotations() {
|
||||
Assert.assertArrayEquals(
|
||||
DECLARED_ANNOTATIONS, AnnotatedElementUtil.findDirectlyAnnotations(Foo.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindDirectlyResolvedAnnotation() {
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation6.class));
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.findDirectlyResolvedAnnotation(Foo.class, Annotation5.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindDirectlyResolvedAnnotations() {
|
||||
Annotation[] resolvedAnnotations = AnnotatedElementUtil.findDirectlyResolvedAnnotations(Foo.class);
|
||||
Map<Class<?>, Annotation> annotationMap = Stream.of(resolvedAnnotations).collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, annotationMap.get(Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION6, annotationMap.get(Annotation6.class));
|
||||
Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Assert.assertNull(annotationMap.get(Annotation1.class));
|
||||
Assert.assertNull(annotationMap.get(Annotation2.class));
|
||||
Assert.assertNull(annotationMap.get(Annotation5.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllDirectlyResolvedAnnotations() {
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation4.class)[0]);
|
||||
Assert.assertEquals(ANNOTATION6, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation6.class)[0]);
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation3.class)[0];
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation1.class).length);
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation2.class).length);
|
||||
Assert.assertEquals(0, AnnotatedElementUtil.findAllDirectlyResolvedAnnotations(Foo.class, Annotation5.class).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAnnotationPresent() {
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation1.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation2.class));
|
||||
Assert.assertTrue(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation3.class));
|
||||
|
||||
Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation4.class));
|
||||
Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation5.class));
|
||||
Assert.assertFalse(AnnotatedElementUtil.isAnnotationPresent(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAnnotation() {
|
||||
Assert.assertEquals(ANNOTATION1, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertEquals(ANNOTATION2, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.getAnnotation(Foo.class, Annotation3.class));
|
||||
|
||||
Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAnnotations() {
|
||||
Annotation[] annotations = AnnotatedElementUtil.getAnnotations(Foo.class);
|
||||
Assert.assertArrayEquals(
|
||||
new Annotation[]{ ANNOTATION3, ANNOTATION2, ANNOTATION1 },
|
||||
annotations
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetResolvedAnnotation() {
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetResolvedAnnotations() {
|
||||
Map<Class<?>, Annotation> annotationMap = Stream.of(AnnotatedElementUtil.getResolvedAnnotations(Foo.class))
|
||||
.collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
|
||||
|
||||
Annotation3 resolvedAnnotation3 = (Annotation3)annotationMap.get(Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = (Annotation2)annotationMap.get(Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = (Annotation1)annotationMap.get(Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertFalse(annotationMap.containsKey(Annotation4.class));
|
||||
Assert.assertFalse(annotationMap.containsKey(Annotation5.class));
|
||||
Assert.assertFalse(annotationMap.containsKey(Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectlyAnnotation() {
|
||||
Assert.assertEquals(ANNOTATION3, AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation3.class));
|
||||
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectlyAnnotations() {
|
||||
Annotation[] annotations = AnnotatedElementUtil.getDirectlyAnnotations(Foo.class);
|
||||
Assert.assertEquals(1, annotations.length);
|
||||
Assert.assertEquals(ANNOTATION3, annotations[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectlyResolvedAnnotation() {
|
||||
Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation2.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation1.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation4.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation5.class));
|
||||
Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation6.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectlyResolvedAnnotations() {
|
||||
Annotation[] annotations = AnnotatedElementUtil.getDirectlyResolvedAnnotations(Foo.class);
|
||||
Assert.assertEquals(1, annotations.length);
|
||||
|
||||
Annotation3 resolvedAnnotation3 = (Annotation3)annotations[0];
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToHierarchyMetaElement() {
|
||||
Assert.assertNotNull(AnnotatedElementUtil.toHierarchyMetaElement(null, false));
|
||||
Assert.assertNotNull(AnnotatedElementUtil.toHierarchyMetaElement(null, true));
|
||||
AnnotatedElement element = AnnotatedElementUtil.toHierarchyMetaElement(Foo.class, false);
|
||||
|
||||
// 带有元注解
|
||||
Assert.assertArrayEquals(ANNOTATIONS, element.getAnnotations());
|
||||
|
||||
// 不带元注解
|
||||
Assert.assertArrayEquals(DECLARED_ANNOTATIONS, element.getDeclaredAnnotations());
|
||||
|
||||
// 解析注解属性
|
||||
AnnotatedElement resolvedElement = AnnotatedElementUtil.toHierarchyMetaElement(Foo.class, true);
|
||||
Annotation3 resolvedAnnotation3 = resolvedElement.getAnnotation(Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = resolvedElement.getAnnotation(Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = resolvedElement.getAnnotation(Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
|
||||
Assert.assertEquals(ANNOTATION4, resolvedElement.getAnnotation(Annotation4.class));
|
||||
Assert.assertEquals(ANNOTATION6, resolvedElement.getAnnotation(Annotation6.class));
|
||||
Assert.assertEquals(ANNOTATION5, resolvedElement.getAnnotation(Annotation5.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToHierarchyElement() {
|
||||
Assert.assertNotNull(AnnotatedElementUtil.toHierarchyElement(Foo.class));
|
||||
AnnotatedElement element = AnnotatedElementUtil.toHierarchyElement(Foo.class);
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION3, ANNOTATION4, ANNOTATION6}, element.getAnnotations());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMetaElement() {
|
||||
Assert.assertNotNull(AnnotatedElementUtil.toMetaElement(null, false));
|
||||
Assert.assertNotNull(AnnotatedElementUtil.toMetaElement(null, true));
|
||||
|
||||
// 不解析注解属性
|
||||
AnnotatedElement element = AnnotatedElementUtil.toMetaElement(Foo.class, false);
|
||||
Assert.assertSame(element, AnnotatedElementUtil.toMetaElement(Foo.class, false)); // 第二次获取时从缓存中获取
|
||||
Assert.assertArrayEquals(new Annotation[]{ANNOTATION3, ANNOTATION2, ANNOTATION1}, element.getAnnotations());
|
||||
|
||||
// 解析注解属性
|
||||
element = AnnotatedElementUtil.toMetaElement(Foo.class, true);
|
||||
Assert.assertSame(element, AnnotatedElementUtil.toMetaElement(Foo.class, true)); // 第二次获取时从缓存中获取
|
||||
Assert.assertEquals(3, element.getAnnotations().length);
|
||||
|
||||
Annotation3 resolvedAnnotation3 = element.getAnnotation(Annotation3.class);
|
||||
Assert.assertNotNull(resolvedAnnotation3);
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value());
|
||||
Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名
|
||||
|
||||
Annotation2 resolvedAnnotation2 = element.getAnnotation(Annotation2.class);
|
||||
Assert.assertNotNull(resolvedAnnotation2);
|
||||
Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖
|
||||
|
||||
Annotation1 resolvedAnnotation1 = element.getAnnotation(Annotation1.class);
|
||||
Assert.assertNotNull(resolvedAnnotation1);
|
||||
Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖
|
||||
Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsElement() {
|
||||
Annotation[] annotations = new Annotation[]{ANNOTATION1, ANNOTATION2};
|
||||
Assert.assertNotNull(AnnotatedElementUtil.asElement());
|
||||
|
||||
AnnotatedElement element = AnnotatedElementUtil.asElement(ANNOTATION1, null, ANNOTATION2);
|
||||
Assert.assertArrayEquals(annotations, element.getAnnotations());
|
||||
Assert.assertArrayEquals(annotations, element.getDeclaredAnnotations());
|
||||
Assert.assertEquals(ANNOTATION1, element.getAnnotation(Annotation1.class));
|
||||
Assert.assertNull(element.getAnnotation(Annotation3.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyElement() {
|
||||
AnnotatedElement element = AnnotatedElementUtil.emptyElement();
|
||||
Assert.assertSame(element, AnnotatedElementUtil.emptyElement());
|
||||
Assert.assertNull(element.getAnnotation(Annotation1.class));
|
||||
Assert.assertEquals(0, element.getAnnotations().length);
|
||||
Assert.assertEquals(0, element.getDeclaredAnnotations().length);
|
||||
}
|
||||
|
||||
// ================= super =================
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation4 {}
|
||||
|
||||
@Annotation4
|
||||
private static class Super {};
|
||||
|
||||
// ================= interface =================
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation5 {}
|
||||
|
||||
@Annotation5
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation6 {}
|
||||
|
||||
@Annotation6
|
||||
private interface Interface {};
|
||||
|
||||
// ================= foo =================
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation1 {
|
||||
@Alias("alias")
|
||||
String value() default "";
|
||||
@Alias("value")
|
||||
String alias() default "";
|
||||
}
|
||||
|
||||
@Annotation1
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation2 {
|
||||
int num() default Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Annotation2
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface Annotation3 {
|
||||
@Alias("alias")
|
||||
String value() default "";
|
||||
@Alias("value")
|
||||
String alias() default "";
|
||||
int num() default Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Annotation3(value = "foo", num = Integer.MAX_VALUE)
|
||||
private static class Foo extends Super implements Interface {}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user