!715 添加了通用的注解扫描器 GenericAnnotationScanner,并在 AnnotationScanner 接口中统一提供了提前配置好的扫描器静态实例

Merge pull request !715 from Createsequence/feat-scanner
This commit is contained in:
Looly 2022-07-19 02:41:45 +00:00 committed by Gitee
commit fad4886722
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
9 changed files with 488 additions and 71 deletions

View File

@ -1,6 +1,9 @@
package cn.hutool.core.annotation;
import cn.hutool.core.annotation.scanner.*;
import cn.hutool.core.annotation.scanner.AnnotationScanner;
import cn.hutool.core.annotation.scanner.MetaAnnotationScanner;
import cn.hutool.core.annotation.scanner.MethodAnnotationScanner;
import cn.hutool.core.annotation.scanner.TypeAnnotationScanner;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Opt;
@ -334,7 +337,7 @@ public class AnnotationUtil {
* @see MetaAnnotationScanner
*/
public static List<Annotation> scanMetaAnnotation(Class<? extends Annotation> annotationType) {
return new MetaAnnotationScanner().getIfSupport(annotationType);
return AnnotationScanner.DIRECTLY_AND_META_ANNOTATION.getAnnotationsIfSupport(annotationType);
}
/**
@ -363,7 +366,7 @@ public class AnnotationUtil {
* @see TypeAnnotationScanner
*/
public static List<Annotation> scanClass(Class<?> targetClass) {
return new TypeAnnotationScanner().getIfSupport(targetClass);
return AnnotationScanner.TYPE_HIERARCHY.getAnnotationsIfSupport(targetClass);
}
/**
@ -391,7 +394,7 @@ public class AnnotationUtil {
* @see MethodAnnotationScanner
*/
public static List<Annotation> scanMethod(Method method) {
return new MethodAnnotationScanner(true).getIfSupport(method);
return AnnotationScanner.TYPE_HIERARCHY.getAnnotationsIfSupport(method);
}
/**
@ -478,14 +481,12 @@ public class AnnotationUtil {
if (ObjectUtil.isNotNull(target)) {
return target;
}
AnnotationScanner[] scanners = new AnnotationScanner[]{
new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner()
};
return AnnotationScanner.scanByAnySupported(annotatedEle, scanners).stream()
.map(annotation -> getSynthesizedAnnotation(annotationType, annotation))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
return AnnotationScanner.DIRECTLY
.getAnnotationsIfSupport(annotatedEle).stream()
.map(annotation -> getSynthesizedAnnotation(annotationType, annotation))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
@ -511,10 +512,8 @@ public class AnnotationUtil {
* @see SynthesizedAggregateAnnotation
*/
public static <T extends Annotation> List<T> getAllSynthesizedAnnotations(AnnotatedElement annotatedEle, Class<T> annotationType) {
AnnotationScanner[] scanners = new AnnotationScanner[]{
new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner()
};
return AnnotationScanner.scanByAnySupported(annotatedEle, scanners).stream()
return AnnotationScanner.DIRECTLY
.getAnnotationsIfSupport(annotatedEle).stream()
.map(annotation -> getSynthesizedAnnotation(annotationType, annotation))
.filter(Objects::nonNull)
.collect(Collectors.toList());
@ -527,7 +526,7 @@ public class AnnotationUtil {
* @return 聚合注解
*/
public static SynthesizedAggregateAnnotation aggregatingFromAnnotation(Annotation... annotations) {
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), EmptyAnnotationScanner.INSTANCE);
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), AnnotationScanner.NOTHING);
}
/**
@ -537,7 +536,7 @@ public class AnnotationUtil {
* @return 聚合注解
*/
public static SynthesizedAggregateAnnotation aggregatingFromAnnotationWithMeta(Annotation... annotations) {
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), new MetaAnnotationScanner());
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), AnnotationScanner.DIRECTLY_AND_META_ANNOTATION);
}
/**

View File

@ -60,9 +60,9 @@ public abstract class AbstractTypeAnnotationScanner<T extends AbstractTypeAnnota
* 构造一个类注解扫描器
*
* @param includeSuperClass 是否允许扫描父类
* @param includeInterfaces 是否允许扫描父接口
* @param filter 过滤器
* @param excludeTypes 不包含的类型
* @param includeInterfaces 是否允许扫描父接口
* @param filter 过滤器
* @param excludeTypes 不包含的类型
*/
@SuppressWarnings("unchecked")
protected AbstractTypeAnnotationScanner(boolean includeSuperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
@ -186,7 +186,7 @@ public abstract class AbstractTypeAnnotationScanner<T extends AbstractTypeAnnota
// 处理层级索引和注解
final Annotation[] targetAnnotations = getAnnotationsFromTargetClass(annotatedEle, index, targetClass);
for (final Annotation annotation : targetAnnotations) {
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) || filter.test(annotation)) {
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
consumer.accept(index, annotation);
}
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Collection;
@ -16,16 +17,120 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 注解扫描器用于从支持的可注解元素上获取所需注解
* <p>注解扫描器用于从支持的可注解元素上获取所需注解
*
* <p>默认提供了以下扫描方式
* <ul>
* <li>{@link #NOTHING}什么都不做什么注解都不扫描</li>
* <li>{@link #DIRECTLY}扫描元素本身直接声明的注解包括父类带有{@link Inherited}被传递到元素上的注解</li>
* <li>
* {@link #DIRECTLY_AND_META_ANNOTATION}扫描元素本身直接声明的注解包括父类带有{@link Inherited}被传递到元素上的注解
* 以及这些注解的元注解
* </li>
* <li>{@link #SUPERCLASS}扫描元素本身以及父类的层级结构中声明的注解</li>
* <li>{@link #SUPERCLASS_AND_META_ANNOTATION}扫描元素本身以及父类的层级结构中声明的注解以及这些注解的元注解</li>
* <li>{@link #INTERFACE}扫描元素本身以及父接口的层级结构中声明的注解</li>
* <li>{@link #INTERFACE_AND_META_ANNOTATION}扫描元素本身以及父接口的层级结构中声明的注解以及这些注解的元注解</li>
* <li>{@link #TYPE_HIERARCHY}扫描元素本身以及父类父接口的层级结构中声明的注解</li>
* <li>{@link #TYPE_HIERARCHY_AND_META_ANNOTATION}扫描元素本身以及父接口父接口的层级结构中声明的注解以及这些注解的元注解</li>
* </ul>
*
* @author huangchengxing
* @see TypeAnnotationScanner
* @see MethodAnnotationScanner
* @see FieldAnnotationScanner
* @see MetaAnnotationScanner
* @see ElementAnnotationScanner
* @see GenericAnnotationScanner
*/
public interface AnnotationScanner {
// ============================ 预置的扫描器实例 ============================
/**
* 不扫描任何注解
*/
AnnotationScanner NOTHING = new EmptyAnnotationScanner();
/**
* 扫描元素本身直接声明的注解包括父类带有{@link Inherited}被传递到元素上的注解的扫描器
*/
AnnotationScanner DIRECTLY = new GenericAnnotationScanner(false, false, false);
/**
* 扫描元素本身直接声明的注解包括父类带有{@link Inherited}被传递到元素上的注解以及这些注解的元注解的扫描器
*/
AnnotationScanner DIRECTLY_AND_META_ANNOTATION = new GenericAnnotationScanner(true, false, false);
/**
* 扫描元素本身以及父类的层级结构中声明的注解的扫描器
*/
AnnotationScanner SUPERCLASS = new GenericAnnotationScanner(false, true, false);
/**
* 扫描元素本身以及父类的层级结构中声明的注解以及这些注解的元注解的扫描器
*/
AnnotationScanner SUPERCLASS_AND_META_ANNOTATION = new GenericAnnotationScanner(true, true, false);
/**
* 扫描元素本身以及父接口的层级结构中声明的注解的扫描器
*/
AnnotationScanner INTERFACE = new GenericAnnotationScanner(false, false, true);
/**
* 扫描元素本身以及父接口的层级结构中声明的注解以及这些注解的元注解的扫描器
*/
AnnotationScanner INTERFACE_AND_META_ANNOTATION = new GenericAnnotationScanner(true, false, true);
/**
* 扫描元素本身以及父类父接口的层级结构中声明的注解的扫描器
*/
AnnotationScanner TYPE_HIERARCHY = new GenericAnnotationScanner(false, true, true);
/**
* 扫描元素本身以及父接口父接口的层级结构中声明的注解以及这些注解的元注解的扫描器
*/
AnnotationScanner TYPE_HIERARCHY_AND_META_ANNOTATION = new GenericAnnotationScanner(true, true, true);
// ============================ 静态方法 ============================
/**
* 给定一组扫描器使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param scanners 注解扫描器
* @return 注解
*/
static List<Annotation> scanByAnySupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.filter(scanner -> scanner.support(annotatedEle))
.findFirst()
.map(scanner -> scanner.getAnnotations(annotatedEle))
.orElseGet(Collections::emptyList);
}
/**
* 根据指定的扫描器扫描元素上可能存在的注解
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param scanners 注解扫描器
* @return 注解
*/
static List<Annotation> scanByAllSupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.map(scanner -> scanner.getAnnotationsIfSupport(annotatedEle))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
// ============================ 抽象方法 ============================
/**
* 判断是否支持扫描该注解元素
*
@ -56,7 +161,7 @@ public interface AnnotationScanner {
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @return 注解
*/
default List<Annotation> getIfSupport(AnnotatedElement annotatedEle) {
default List<Annotation> getAnnotationsIfSupport(AnnotatedElement annotatedEle) {
return support(annotatedEle) ? getAnnotations(annotatedEle) : Collections.emptyList();
}
@ -90,39 +195,4 @@ public interface AnnotationScanner {
}
}
/**
* 给定一组扫描器使用第一个支持处理该类型元素的扫描器获取元素上可能存在的注解
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param scanners 注解扫描器
* @return 注解
*/
static List<Annotation> scanByAnySupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.filter(scanner -> scanner.support(annotatedEle))
.findFirst()
.map(scanner -> scanner.getAnnotations(annotatedEle))
.orElseGet(Collections::emptyList);
}
/**
* 根据指定的扫描器扫描元素上可能存在的注解
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param scanners 注解扫描器
* @return 注解
*/
static List<Annotation> scanByAllScanner(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.map(scanner -> scanner.getIfSupport(annotatedEle))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,44 @@
package cn.hutool.core.annotation.scanner;
import cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* 扫描{@link AnnotatedElement}上的注解不支持处理层级对象
*
* @author huangchengxing
*/
public class ElementAnnotationScanner implements AnnotationScanner {
/**
* 判断是否支持扫描该注解元素仅当注解元素不为空时返回{@code true}
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @return 是否支持扫描该注解元素
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return ObjectUtil.isNotNull(annotatedEle);
}
/**
* 扫描{@link AnnotatedElement}上直接声明的注解调用前需要确保调用{@link #support(AnnotatedElement)}返回为true
*
* @param consumer 对获取到的注解和注解对应的层级索引的处理
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param filter 注解过滤器无法通过过滤器的注解不会被处理该参数允许为空
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, t -> true);
Stream.of(annotatedEle.getAnnotations())
.filter(filter)
.forEach(annotation -> consumer.accept(0, annotation));
}
}

View File

@ -14,8 +14,6 @@ import java.util.function.Predicate;
*/
public class EmptyAnnotationScanner implements AnnotationScanner {
public static final EmptyAnnotationScanner INSTANCE = new EmptyAnnotationScanner();
@Override
public boolean support(AnnotatedElement annotatedEle) {
return true;

View File

@ -0,0 +1,149 @@
package cn.hutool.core.annotation.scanner;
import cn.hutool.core.map.multi.ListValueMap;
import cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
* <p>通用注解扫描器支持按不同的层级结构扫描{@link AnnotatedElement}上的注解
*
* <p>{@link AnnotatedElement}类型不同时层级结构指向的对象将有所区别
* <ul>
* <li>
* 当元素为{@link Method}此处层级结构指声明方法的类的层级结构
* 扫描器将从层级结构中寻找与该方法签名相同的方法并对其进行扫描
* </li>
* <li>
* 当元素为{@link Class}此处层级结构即指类本身与其父类父接口共同构成的层级结构
* 扫描器将扫描层级结构中类接口声明的注解
* </li>
* <li>当元素不为{@link Method}{@link Class}则其层级结构仅有其本身一层</li>
* </ul>
* 此外扫描器支持在获取到层级结构中的注解对象后再对注解对象的元注解进行扫描
*
* @author huangchengxing
* @see TypeAnnotationScanner
* @see MethodAnnotationScanner
* @see MetaAnnotationScanner
* @see ElementAnnotationScanner
*/
public class GenericAnnotationScanner implements AnnotationScanner {
/**
* 类型扫描器
*/
private final AnnotationScanner typeScanner;
/**
* 方法扫描器
*/
private final AnnotationScanner methodScanner;
/**
* 元注解扫描器
*/
private final AnnotationScanner metaScanner;
/**
* 普通元素扫描器
*/
private final AnnotationScanner elementScanner;
/**
* 通用注解扫描器支持扫描所有类型的{@link AnnotatedElement}
*
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @return 是否支持扫描该注解元素
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return true;
}
/**
* 构造一个通用注解扫描器
*
* @param enableScanMetaAnnotation 是否扫描注解上的元注解
* @param enableScanSupperClass 是否扫描父类
* @param enableScanSupperInterface 是否扫描父接口
*/
public GenericAnnotationScanner(
boolean enableScanMetaAnnotation,
boolean enableScanSupperClass,
boolean enableScanSupperInterface) {
this.metaScanner = enableScanMetaAnnotation ? new MetaAnnotationScanner() : new EmptyAnnotationScanner();
this.typeScanner = new TypeAnnotationScanner(
enableScanSupperClass, enableScanSupperInterface, a -> true, Collections.emptySet()
);
this.methodScanner = new MethodAnnotationScanner(
enableScanSupperClass, enableScanSupperInterface, a -> true, Collections.emptySet()
);
this.elementScanner = new ElementAnnotationScanner();
}
/**
* 扫描注解元素的层级结构若存在然后对获取到的注解和注解对应的层级索引进行处理
*
* @param consumer 对获取到的注解和注解对应的层级索引的处理
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param filter 注解过滤器无法通过过滤器的注解不会被处理该参数允许为空
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, t -> true);
if (ObjectUtil.isNull(annotatedEle)) {
return;
}
// 注解元素是类
if (annotatedEle instanceof Class) {
scanElements(typeScanner, consumer, annotatedEle, filter);
}
// 注解元素是方法
else if (annotatedEle instanceof Method) {
scanElements(methodScanner, consumer, annotatedEle, filter);
}
// 注解元素是其他类型
else {
scanElements(elementScanner, consumer, annotatedEle, filter);
}
}
/**
* 扫描注解类的层级结构若存在然后对获取到的注解和注解对应的层级索引进行处理
*
* @param scanner 使用的扫描器
* @param consumer 对获取到的注解和注解对应的层级索引的处理
* @param annotatedEle {@link AnnotatedElement}可以是ClassMethodFieldConstructorReflectPermission
* @param filter 注解过滤器无法通过过滤器的注解不会被处理该参数允许为空
*/
private void scanElements(
AnnotationScanner scanner,
BiConsumer<Integer, Annotation> consumer,
AnnotatedElement annotatedEle,
Predicate<Annotation> filter) {
// 扫描类上注解
final ListValueMap<Integer, Annotation> classAnnotations = new ListValueMap<>(new LinkedHashMap<>());
scanner.scan((index, annotation) -> {
if (filter.test(annotation)) {
classAnnotations.putValue(index, annotation);
}
}, annotatedEle, filter);
// 扫描元注解
classAnnotations.forEach((index, annotations) ->
annotations.forEach(annotation -> {
consumer.accept(index, annotation);
metaScanner.scan(consumer, annotation.annotationType(), filter);
})
);
}
}

View File

@ -20,14 +20,10 @@ import java.util.stream.Stream;
public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner<MethodAnnotationScanner> implements AnnotationScanner {
/**
* 构造一个方法注解扫描器
*
* @param scanSameSignatureMethod 是否扫描类层级结构中具有相同方法签名的方法
* @param filter 过滤器
* @param excludeTypes 不包含的类型
* 构造一个类注解扫描器仅扫描该方法上直接声明的注解
*/
public MethodAnnotationScanner(boolean scanSameSignatureMethod, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(scanSameSignatureMethod, scanSameSignatureMethod, filter, excludeTypes);
public MethodAnnotationScanner() {
this(false);
}
/**
@ -40,10 +36,26 @@ public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner<Metho
}
/**
* 构造一个类注解扫描器仅扫描该方法上直接声明的注解
* 构造一个方法注解扫描器
*
* @param scanSameSignatureMethod 是否扫描类层级结构中具有相同方法签名的方法
* @param filter 过滤器
* @param excludeTypes 不包含的类型
*/
public MethodAnnotationScanner() {
this(false);
public MethodAnnotationScanner(boolean scanSameSignatureMethod, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(scanSameSignatureMethod, scanSameSignatureMethod, filter, excludeTypes);
}
/**
* 构造一个方法注解扫描器
*
* @param includeSuperClass 是否允许扫描父类中具有相同方法签名的方法
* @param includeInterfaces 是否允许扫描父接口中具有相同方法签名的方法
* @param filter 过滤器
* @param excludeTypes 不包含的类型
*/
public MethodAnnotationScanner(boolean includeSuperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(includeSuperClass, includeInterfaces, filter, excludeTypes);
}
/**

View File

@ -0,0 +1,60 @@
package cn.hutool.core.annotation.scanner;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ElementAnnotationScannerTest {
@Test
public void supportTest() {
final ElementAnnotationScanner scanner = new ElementAnnotationScanner();
Assert.assertTrue(scanner.support(ReflectUtil.getField(FieldAnnotationScannerTest.Example.class, "id")));
Assert.assertTrue(scanner.support(ReflectUtil.getMethod(FieldAnnotationScannerTest.Example.class, "getId")));
Assert.assertFalse(scanner.support(null));
Assert.assertTrue(scanner.support(FieldAnnotationScannerTest.Example.class));
}
@Test
public void getAnnotationsTest() {
final ElementAnnotationScanner scanner = new ElementAnnotationScanner();
final Field field = ReflectUtil.getField(FieldAnnotationScannerTest.Example.class, "id");
Assert.assertNotNull(field);
Assert.assertTrue(scanner.support(field));
List<Annotation> annotations = scanner.getAnnotations(field);
Assert.assertEquals(1, annotations.size());
Assert.assertEquals(AnnotationForScannerTest.class, CollUtil.getFirst(annotations).annotationType());
}
@Test
public void scanTest() {
final ElementAnnotationScanner scanner = new ElementAnnotationScanner();
final Field field = ReflectUtil.getField(FieldAnnotationScannerTest.Example.class, "id");
final Map<Integer, List<Annotation>> map = new HashMap<>();
scanner.scan(
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
field, null
);
Assert.assertEquals(1, map.size());
Assert.assertEquals(1, map.get(0).size());
Assert.assertEquals(AnnotationForScannerTest.class, map.get(0).get(0).annotationType());
}
public static class Example {
@AnnotationForScannerTest
private Integer id;
public Integer getId() {
return id;
}
}
}

View File

@ -0,0 +1,85 @@
package cn.hutool.core.annotation.scanner;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.*;
import java.util.List;
public class GenericAnnotationScannerTest {
@Test
public void scanDirectlyTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(false, false, false);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(1, annotations.size());
}
@Test
public void scanDirectlyAndMetaAnnotationTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(true, false, false);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(2, annotations.size());
}
@Test
public void scanSuperclassTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(false, true, false);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(2, annotations.size());
}
@Test
public void scanSuperclassAndMetaAnnotationTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(true, true, false);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(4, annotations.size());
}
@Test
public void scanInterfaceTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(false, false, true);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(2, annotations.size());
}
@Test
public void scanInterfaceAndMetaAnnotationTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(true, false, true);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(4, annotations.size());
}
@Test
public void scanTypeHierarchyTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(false, true, true);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(3, annotations.size());
}
@Test
public void scanTypeHierarchyAndMetaAnnotationTest() {
final GenericAnnotationScanner scanner = new GenericAnnotationScanner(true, true, true);
final List<Annotation> annotations = scanner.getAnnotations(ClassForTest.class);
Assert.assertEquals(6, annotations.size());
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MetaAnnotationForTest { }
@MetaAnnotationForTest
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationForTest { }
@AnnotationForTest
static class ClassForTest extends SupperForTest implements InterfaceForTest { }
@AnnotationForTest
static class SupperForTest { }
@AnnotationForTest
interface InterfaceForTest { }
}