添加AnnotatedElementUtil工具类

This commit is contained in:
huangchengxing 2022-09-13 13:59:01 +08:00
parent 4b38bc31d2
commit 6c6eeb49d7
2 changed files with 1095 additions and 0 deletions

View File

@ -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];
}
}
}

View File

@ -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 {}
}