Merge branch '5.2.x'
This commit is contained in:
commit
8a394c2b07
|
|
@ -23,7 +23,6 @@ import java.lang.reflect.Method;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.Ordered;
|
||||
|
|
@ -75,70 +74,49 @@ abstract class AnnotationsScanner {
|
|||
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
|
||||
AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
return scan(context, source, searchStrategy, processor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the hierarchy of the specified element for relevant annotations and
|
||||
* call the processor as required.
|
||||
* @param context an optional context object that will be passed back to the
|
||||
* processor
|
||||
* @param source the source element to scan
|
||||
* @param searchStrategy the search strategy to use
|
||||
* @param processor the processor that receives the annotations
|
||||
* @param classFilter an optional filter that can be used to entirely filter
|
||||
* out a specific class from the hierarchy
|
||||
* @return the result of {@link AnnotationsProcessor#finish(Object)}
|
||||
*/
|
||||
@Nullable
|
||||
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
|
||||
R result = process(context, source, searchStrategy, processor, classFilter);
|
||||
R result = process(context, source, searchStrategy, processor);
|
||||
return processor.finish(result);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <C, R> R process(C context, AnnotatedElement source,
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor,
|
||||
@Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
if (source instanceof Class) {
|
||||
return processClass(context, (Class<?>) source, searchStrategy, processor, classFilter);
|
||||
return processClass(context, (Class<?>) source, searchStrategy, processor);
|
||||
}
|
||||
if (source instanceof Method) {
|
||||
return processMethod(context, (Method) source, searchStrategy, processor, classFilter);
|
||||
return processMethod(context, (Method) source, searchStrategy, processor);
|
||||
}
|
||||
return processElement(context, source, processor, classFilter);
|
||||
return processElement(context, source, processor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <C, R> R processClass(C context, Class<?> source,
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor,
|
||||
@Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
switch (searchStrategy) {
|
||||
case DIRECT:
|
||||
return processElement(context, source, processor, classFilter);
|
||||
return processElement(context, source, processor);
|
||||
case INHERITED_ANNOTATIONS:
|
||||
return processClassInheritedAnnotations(context, source, searchStrategy, processor, classFilter);
|
||||
return processClassInheritedAnnotations(context, source, searchStrategy, processor);
|
||||
case SUPERCLASS:
|
||||
return processClassHierarchy(context, source, processor, classFilter, false, false);
|
||||
return processClassHierarchy(context, source, processor, false, false);
|
||||
case TYPE_HIERARCHY:
|
||||
return processClassHierarchy(context, source, processor, classFilter, true, false);
|
||||
return processClassHierarchy(context, source, processor, true, false);
|
||||
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES:
|
||||
return processClassHierarchy(context, source, processor, classFilter, true, true);
|
||||
return processClassHierarchy(context, source, processor, true, true);
|
||||
}
|
||||
throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <C, R> R processClassInheritedAnnotations(C context, Class<?> source,
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
try {
|
||||
if (isWithoutHierarchy(source, searchStrategy)) {
|
||||
return processElement(context, source, processor, classFilter);
|
||||
return processElement(context, source, processor);
|
||||
}
|
||||
Annotation[] relevant = null;
|
||||
int remaining = Integer.MAX_VALUE;
|
||||
|
|
@ -150,14 +128,7 @@ abstract class AnnotationsScanner {
|
|||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
if (isFiltered(source, context, classFilter)) {
|
||||
// Skip the current level in the class hierarchy.
|
||||
source = source.getSuperclass();
|
||||
aggregateIndex++;
|
||||
continue;
|
||||
}
|
||||
Annotation[] declaredAnnotations =
|
||||
getDeclaredAnnotations(context, source, classFilter, true);
|
||||
Annotation[] declaredAnnotations = getDeclaredAnnotations(source, true);
|
||||
if (relevant == null && declaredAnnotations.length > 0) {
|
||||
relevant = root.getAnnotations();
|
||||
remaining = relevant.length;
|
||||
|
|
@ -195,17 +166,15 @@ abstract class AnnotationsScanner {
|
|||
|
||||
@Nullable
|
||||
private static <C, R> R processClassHierarchy(C context, Class<?> source,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter,
|
||||
boolean includeInterfaces, boolean includeEnclosing) {
|
||||
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
|
||||
|
||||
return processClassHierarchy(context, new int[] {0}, source, processor,
|
||||
classFilter, includeInterfaces, includeEnclosing);
|
||||
includeInterfaces, includeEnclosing);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter,
|
||||
boolean includeInterfaces, boolean includeEnclosing) {
|
||||
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
|
||||
|
||||
try {
|
||||
R result = processor.doWithAggregate(context, aggregateIndex[0]);
|
||||
|
|
@ -215,7 +184,7 @@ abstract class AnnotationsScanner {
|
|||
if (hasPlainJavaAnnotationsOnly(source)) {
|
||||
return null;
|
||||
}
|
||||
Annotation[] annotations = getDeclaredAnnotations(context, source, classFilter, false);
|
||||
Annotation[] annotations = getDeclaredAnnotations(source, false);
|
||||
result = processor.doWithAnnotations(context, aggregateIndex[0], source, annotations);
|
||||
if (result != null) {
|
||||
return result;
|
||||
|
|
@ -224,7 +193,7 @@ abstract class AnnotationsScanner {
|
|||
if (includeInterfaces) {
|
||||
for (Class<?> interfaceType : source.getInterfaces()) {
|
||||
R interfacesResult = processClassHierarchy(context, aggregateIndex,
|
||||
interfaceType, processor, classFilter, true, includeEnclosing);
|
||||
interfaceType, processor, true, includeEnclosing);
|
||||
if (interfacesResult != null) {
|
||||
return interfacesResult;
|
||||
}
|
||||
|
|
@ -233,7 +202,7 @@ abstract class AnnotationsScanner {
|
|||
Class<?> superclass = source.getSuperclass();
|
||||
if (superclass != Object.class && superclass != null) {
|
||||
R superclassResult = processClassHierarchy(context, aggregateIndex,
|
||||
superclass, processor, classFilter, includeInterfaces, includeEnclosing);
|
||||
superclass, processor, includeInterfaces, includeEnclosing);
|
||||
if (superclassResult != null) {
|
||||
return superclassResult;
|
||||
}
|
||||
|
|
@ -248,7 +217,7 @@ abstract class AnnotationsScanner {
|
|||
Class<?> enclosingClass = source.getEnclosingClass();
|
||||
if (enclosingClass != null) {
|
||||
R enclosingResult = processClassHierarchy(context, aggregateIndex,
|
||||
enclosingClass, processor, classFilter, includeInterfaces, true);
|
||||
enclosingClass, processor, includeInterfaces, true);
|
||||
if (enclosingResult != null) {
|
||||
return enclosingResult;
|
||||
}
|
||||
|
|
@ -267,32 +236,31 @@ abstract class AnnotationsScanner {
|
|||
|
||||
@Nullable
|
||||
private static <C, R> R processMethod(C context, Method source,
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor,
|
||||
@Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
switch (searchStrategy) {
|
||||
case DIRECT:
|
||||
case INHERITED_ANNOTATIONS:
|
||||
return processMethodInheritedAnnotations(context, source, processor, classFilter);
|
||||
return processMethodInheritedAnnotations(context, source, processor);
|
||||
case SUPERCLASS:
|
||||
return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(),
|
||||
processor, classFilter, source, false);
|
||||
processor, source, false);
|
||||
case TYPE_HIERARCHY:
|
||||
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES:
|
||||
return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(),
|
||||
processor, classFilter, source, true);
|
||||
processor, source, true);
|
||||
}
|
||||
throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <C, R> R processMethodInheritedAnnotations(C context, Method source,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
try {
|
||||
R result = processor.doWithAggregate(context, 0);
|
||||
return (result != null ? result :
|
||||
processMethodAnnotations(context, 0, source, processor, classFilter));
|
||||
processMethodAnnotations(context, 0, source, processor));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
AnnotationUtils.handleIntrospectionFailure(source, ex);
|
||||
|
|
@ -302,8 +270,7 @@ abstract class AnnotationsScanner {
|
|||
|
||||
@Nullable
|
||||
private static <C, R> R processMethodHierarchy(C context, int[] aggregateIndex,
|
||||
Class<?> sourceClass, AnnotationsProcessor<C, R> processor,
|
||||
@Nullable BiPredicate<C, Class<?>> classFilter, Method rootMethod,
|
||||
Class<?> sourceClass, AnnotationsProcessor<C, R> processor, Method rootMethod,
|
||||
boolean includeInterfaces) {
|
||||
|
||||
try {
|
||||
|
|
@ -317,17 +284,17 @@ abstract class AnnotationsScanner {
|
|||
boolean calledProcessor = false;
|
||||
if (sourceClass == rootMethod.getDeclaringClass()) {
|
||||
result = processMethodAnnotations(context, aggregateIndex[0],
|
||||
rootMethod, processor, classFilter);
|
||||
rootMethod, processor);
|
||||
calledProcessor = true;
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Method candidateMethod : getBaseTypeMethods(context, sourceClass, classFilter)) {
|
||||
for (Method candidateMethod : getBaseTypeMethods(context, sourceClass)) {
|
||||
if (candidateMethod != null && isOverride(rootMethod, candidateMethod)) {
|
||||
result = processMethodAnnotations(context, aggregateIndex[0],
|
||||
candidateMethod, processor, classFilter);
|
||||
candidateMethod, processor);
|
||||
calledProcessor = true;
|
||||
if (result != null) {
|
||||
return result;
|
||||
|
|
@ -344,7 +311,7 @@ abstract class AnnotationsScanner {
|
|||
if (includeInterfaces) {
|
||||
for (Class<?> interfaceType : sourceClass.getInterfaces()) {
|
||||
R interfacesResult = processMethodHierarchy(context, aggregateIndex,
|
||||
interfaceType, processor, classFilter, rootMethod, true);
|
||||
interfaceType, processor, rootMethod, true);
|
||||
if (interfacesResult != null) {
|
||||
return interfacesResult;
|
||||
}
|
||||
|
|
@ -353,7 +320,7 @@ abstract class AnnotationsScanner {
|
|||
Class<?> superclass = sourceClass.getSuperclass();
|
||||
if (superclass != Object.class && superclass != null) {
|
||||
R superclassResult = processMethodHierarchy(context, aggregateIndex,
|
||||
superclass, processor, classFilter, rootMethod, includeInterfaces);
|
||||
superclass, processor, rootMethod, includeInterfaces);
|
||||
if (superclassResult != null) {
|
||||
return superclassResult;
|
||||
}
|
||||
|
|
@ -365,11 +332,8 @@ abstract class AnnotationsScanner {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static <C> Method[] getBaseTypeMethods(
|
||||
C context, Class<?> baseType, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
|
||||
if (baseType == Object.class || hasPlainJavaAnnotationsOnly(baseType) ||
|
||||
isFiltered(baseType, context, classFilter)) {
|
||||
private static <C> Method[] getBaseTypeMethods(C context, Class<?> baseType) {
|
||||
if (baseType == Object.class || hasPlainJavaAnnotationsOnly(baseType)) {
|
||||
return NO_METHODS;
|
||||
}
|
||||
|
||||
|
|
@ -433,16 +397,16 @@ abstract class AnnotationsScanner {
|
|||
|
||||
@Nullable
|
||||
private static <C, R> R processMethodAnnotations(C context, int aggregateIndex, Method source,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
Annotation[] annotations = getDeclaredAnnotations(context, source, classFilter, false);
|
||||
Annotation[] annotations = getDeclaredAnnotations(source, false);
|
||||
R result = processor.doWithAnnotations(context, aggregateIndex, source, annotations);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(source);
|
||||
if (bridgedMethod != source) {
|
||||
Annotation[] bridgedAnnotations = getDeclaredAnnotations(context, bridgedMethod, classFilter, true);
|
||||
Annotation[] bridgedAnnotations = getDeclaredAnnotations(bridgedMethod, true);
|
||||
for (int i = 0; i < bridgedAnnotations.length; i++) {
|
||||
if (ObjectUtils.containsElement(annotations, bridgedAnnotations[i])) {
|
||||
bridgedAnnotations[i] = null;
|
||||
|
|
@ -455,12 +419,12 @@ abstract class AnnotationsScanner {
|
|||
|
||||
@Nullable
|
||||
private static <C, R> R processElement(C context, AnnotatedElement source,
|
||||
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
AnnotationsProcessor<C, R> processor) {
|
||||
|
||||
try {
|
||||
R result = processor.doWithAggregate(context, 0);
|
||||
return (result != null ? result : processor.doWithAnnotations(
|
||||
context, 0, source, getDeclaredAnnotations(context, source, classFilter, false)));
|
||||
context, 0, source, getDeclaredAnnotations(source, false)));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
AnnotationUtils.handleIntrospectionFailure(source, ex);
|
||||
|
|
@ -468,18 +432,6 @@ abstract class AnnotationsScanner {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static <C, R> Annotation[] getDeclaredAnnotations(C context,
|
||||
AnnotatedElement source, @Nullable BiPredicate<C, Class<?>> classFilter, boolean copy) {
|
||||
|
||||
if (source instanceof Class && isFiltered((Class<?>) source, context, classFilter)) {
|
||||
return NO_ANNOTATIONS;
|
||||
}
|
||||
if (source instanceof Method && isFiltered(((Method) source).getDeclaringClass(), context, classFilter)) {
|
||||
return NO_ANNOTATIONS;
|
||||
}
|
||||
return getDeclaredAnnotations(source, copy);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
static <A extends Annotation> A getDeclaredAnnotation(AnnotatedElement source, Class<A> annotationType) {
|
||||
|
|
@ -525,12 +477,6 @@ abstract class AnnotationsScanner {
|
|||
return annotations.clone();
|
||||
}
|
||||
|
||||
private static <C> boolean isFiltered(
|
||||
Class<?> sourceClass, C context, @Nullable BiPredicate<C, Class<?>> classFilter) {
|
||||
|
||||
return (classFilter != null && classFilter.test(context, sourceClass));
|
||||
}
|
||||
|
||||
private static boolean isIgnorable(Class<?> annotationType) {
|
||||
return AnnotationFilter.PLAIN.matches(annotationType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,51 +128,6 @@ class AnnotationsScannerTests {
|
|||
assertThat(scan(source, SearchStrategy.INHERITED_ANNOTATIONS)).containsExactly("0:TestInheritedAnnotation2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inheritedAnnotationsStrategyOnClassWithAllClassesFilteredOut() {
|
||||
List<String> annotationsFound = new ArrayList<>();
|
||||
String scanResult = AnnotationsScanner.scan(this, WithSingleSuperclass.class,
|
||||
SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
(context, aggregateIndex, source, annotations) -> {
|
||||
trackIndexedAnnotations(aggregateIndex, annotations, annotationsFound);
|
||||
return null; // continue searching
|
||||
},
|
||||
(context, clazz) -> true // filter out all classes
|
||||
);
|
||||
assertThat(annotationsFound).isEmpty();
|
||||
assertThat(scanResult).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void inheritedAnnotationsStrategyOnClassWithSourceClassFilteredOut() {
|
||||
List<String> annotationsFound = new ArrayList<>();
|
||||
String scanResult = AnnotationsScanner.scan(this, WithSingleSuperclass.class,
|
||||
SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
(context, aggregateIndex, source, annotations) -> {
|
||||
trackIndexedAnnotations(aggregateIndex, annotations, annotationsFound);
|
||||
return null; // continue searching
|
||||
},
|
||||
(context, clazz) -> clazz == WithSingleSuperclass.class
|
||||
);
|
||||
assertThat(annotationsFound).containsExactly(/* "0:TestAnnotation1", */ "1:TestInheritedAnnotation2");
|
||||
assertThat(scanResult).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void inheritedAnnotationsStrategyInClassHierarchyWithSuperSuperclassFilteredOut() {
|
||||
List<String> annotationsFound = new ArrayList<>();
|
||||
String scanResult = AnnotationsScanner.scan(this, WithHierarchy.class,
|
||||
SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
(context, aggregateIndex, source, annotations) -> {
|
||||
trackIndexedAnnotations(aggregateIndex, annotations, annotationsFound);
|
||||
return null; // continue searching
|
||||
},
|
||||
(context, clazz) -> clazz == HierarchySuperSuperclass.class
|
||||
);
|
||||
assertThat(annotationsFound).containsExactly("0:TestAnnotation1", "1:TestInheritedAnnotation2");
|
||||
assertThat(scanResult).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void superclassStrategyOnClassWhenNotAnnotatedScansNone() {
|
||||
Class<?> source = WithNoAnnotations.class;
|
||||
|
|
|
|||
Loading…
Reference in New Issue