Browse Source

Merge branch '5.2.x'

pull/25487/head
Sam Brannen 6 years ago
parent
commit
8a394c2b07
  1. 134
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java
  2. 45
      spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java

134
spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java

@ -23,7 +23,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.function.BiPredicate;
import org.springframework.core.BridgeMethodResolver; import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -75,70 +74,49 @@ abstract class AnnotationsScanner {
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy, static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
AnnotationsProcessor<C, R> processor) { AnnotationsProcessor<C, R> processor) {
return scan(context, source, searchStrategy, processor, null); R result = process(context, source, searchStrategy, processor);
}
/**
* 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);
return processor.finish(result); return processor.finish(result);
} }
@Nullable @Nullable
private static <C, R> R process(C context, AnnotatedElement source, private static <C, R> R process(C context, AnnotatedElement source,
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor, SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
@Nullable BiPredicate<C, Class<?>> classFilter) {
if (source instanceof Class) { if (source instanceof Class) {
return processClass(context, (Class<?>) source, searchStrategy, processor, classFilter); return processClass(context, (Class<?>) source, searchStrategy, processor);
} }
if (source instanceof Method) { 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 @Nullable
private static <C, R> R processClass(C context, Class<?> source, private static <C, R> R processClass(C context, Class<?> source,
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor, SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
@Nullable BiPredicate<C, Class<?>> classFilter) {
switch (searchStrategy) { switch (searchStrategy) {
case DIRECT: case DIRECT:
return processElement(context, source, processor, classFilter); return processElement(context, source, processor);
case INHERITED_ANNOTATIONS: case INHERITED_ANNOTATIONS:
return processClassInheritedAnnotations(context, source, searchStrategy, processor, classFilter); return processClassInheritedAnnotations(context, source, searchStrategy, processor);
case SUPERCLASS: case SUPERCLASS:
return processClassHierarchy(context, source, processor, classFilter, false, false); return processClassHierarchy(context, source, processor, false, false);
case TYPE_HIERARCHY: case TYPE_HIERARCHY:
return processClassHierarchy(context, source, processor, classFilter, true, false); return processClassHierarchy(context, source, processor, true, false);
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES: 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); throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
} }
@Nullable @Nullable
private static <C, R> R processClassInheritedAnnotations(C context, Class<?> source, 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 { try {
if (isWithoutHierarchy(source, searchStrategy)) { if (isWithoutHierarchy(source, searchStrategy)) {
return processElement(context, source, processor, classFilter); return processElement(context, source, processor);
} }
Annotation[] relevant = null; Annotation[] relevant = null;
int remaining = Integer.MAX_VALUE; int remaining = Integer.MAX_VALUE;
@ -150,14 +128,7 @@ abstract class AnnotationsScanner {
if (result != null) { if (result != null) {
return result; return result;
} }
if (isFiltered(source, context, classFilter)) { Annotation[] declaredAnnotations = getDeclaredAnnotations(source, true);
// Skip the current level in the class hierarchy.
source = source.getSuperclass();
aggregateIndex++;
continue;
}
Annotation[] declaredAnnotations =
getDeclaredAnnotations(context, source, classFilter, true);
if (relevant == null && declaredAnnotations.length > 0) { if (relevant == null && declaredAnnotations.length > 0) {
relevant = root.getAnnotations(); relevant = root.getAnnotations();
remaining = relevant.length; remaining = relevant.length;
@ -195,17 +166,15 @@ abstract class AnnotationsScanner {
@Nullable @Nullable
private static <C, R> R processClassHierarchy(C context, Class<?> source, private static <C, R> R processClassHierarchy(C context, Class<?> source,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter, AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
boolean includeInterfaces, boolean includeEnclosing) {
return processClassHierarchy(context, new int[] {0}, source, processor, return processClassHierarchy(context, new int[] {0}, source, processor,
classFilter, includeInterfaces, includeEnclosing); includeInterfaces, includeEnclosing);
} }
@Nullable @Nullable
private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source, private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter, AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
boolean includeInterfaces, boolean includeEnclosing) {
try { try {
R result = processor.doWithAggregate(context, aggregateIndex[0]); R result = processor.doWithAggregate(context, aggregateIndex[0]);
@ -215,7 +184,7 @@ abstract class AnnotationsScanner {
if (hasPlainJavaAnnotationsOnly(source)) { if (hasPlainJavaAnnotationsOnly(source)) {
return null; return null;
} }
Annotation[] annotations = getDeclaredAnnotations(context, source, classFilter, false); Annotation[] annotations = getDeclaredAnnotations(source, false);
result = processor.doWithAnnotations(context, aggregateIndex[0], source, annotations); result = processor.doWithAnnotations(context, aggregateIndex[0], source, annotations);
if (result != null) { if (result != null) {
return result; return result;
@ -224,7 +193,7 @@ abstract class AnnotationsScanner {
if (includeInterfaces) { if (includeInterfaces) {
for (Class<?> interfaceType : source.getInterfaces()) { for (Class<?> interfaceType : source.getInterfaces()) {
R interfacesResult = processClassHierarchy(context, aggregateIndex, R interfacesResult = processClassHierarchy(context, aggregateIndex,
interfaceType, processor, classFilter, true, includeEnclosing); interfaceType, processor, true, includeEnclosing);
if (interfacesResult != null) { if (interfacesResult != null) {
return interfacesResult; return interfacesResult;
} }
@ -233,7 +202,7 @@ abstract class AnnotationsScanner {
Class<?> superclass = source.getSuperclass(); Class<?> superclass = source.getSuperclass();
if (superclass != Object.class && superclass != null) { if (superclass != Object.class && superclass != null) {
R superclassResult = processClassHierarchy(context, aggregateIndex, R superclassResult = processClassHierarchy(context, aggregateIndex,
superclass, processor, classFilter, includeInterfaces, includeEnclosing); superclass, processor, includeInterfaces, includeEnclosing);
if (superclassResult != null) { if (superclassResult != null) {
return superclassResult; return superclassResult;
} }
@ -248,7 +217,7 @@ abstract class AnnotationsScanner {
Class<?> enclosingClass = source.getEnclosingClass(); Class<?> enclosingClass = source.getEnclosingClass();
if (enclosingClass != null) { if (enclosingClass != null) {
R enclosingResult = processClassHierarchy(context, aggregateIndex, R enclosingResult = processClassHierarchy(context, aggregateIndex,
enclosingClass, processor, classFilter, includeInterfaces, true); enclosingClass, processor, includeInterfaces, true);
if (enclosingResult != null) { if (enclosingResult != null) {
return enclosingResult; return enclosingResult;
} }
@ -267,32 +236,31 @@ abstract class AnnotationsScanner {
@Nullable @Nullable
private static <C, R> R processMethod(C context, Method source, private static <C, R> R processMethod(C context, Method source,
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor, SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor) {
@Nullable BiPredicate<C, Class<?>> classFilter) {
switch (searchStrategy) { switch (searchStrategy) {
case DIRECT: case DIRECT:
case INHERITED_ANNOTATIONS: case INHERITED_ANNOTATIONS:
return processMethodInheritedAnnotations(context, source, processor, classFilter); return processMethodInheritedAnnotations(context, source, processor);
case SUPERCLASS: case SUPERCLASS:
return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(), return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(),
processor, classFilter, source, false); processor, source, false);
case TYPE_HIERARCHY: case TYPE_HIERARCHY:
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES: case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES:
return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(), return processMethodHierarchy(context, new int[] {0}, source.getDeclaringClass(),
processor, classFilter, source, true); processor, source, true);
} }
throw new IllegalStateException("Unsupported search strategy " + searchStrategy); throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
} }
@Nullable @Nullable
private static <C, R> R processMethodInheritedAnnotations(C context, Method source, private static <C, R> R processMethodInheritedAnnotations(C context, Method source,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) { AnnotationsProcessor<C, R> processor) {
try { try {
R result = processor.doWithAggregate(context, 0); R result = processor.doWithAggregate(context, 0);
return (result != null ? result : return (result != null ? result :
processMethodAnnotations(context, 0, source, processor, classFilter)); processMethodAnnotations(context, 0, source, processor));
} }
catch (Throwable ex) { catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex); AnnotationUtils.handleIntrospectionFailure(source, ex);
@ -302,8 +270,7 @@ abstract class AnnotationsScanner {
@Nullable @Nullable
private static <C, R> R processMethodHierarchy(C context, int[] aggregateIndex, private static <C, R> R processMethodHierarchy(C context, int[] aggregateIndex,
Class<?> sourceClass, AnnotationsProcessor<C, R> processor, Class<?> sourceClass, AnnotationsProcessor<C, R> processor, Method rootMethod,
@Nullable BiPredicate<C, Class<?>> classFilter, Method rootMethod,
boolean includeInterfaces) { boolean includeInterfaces) {
try { try {
@ -317,17 +284,17 @@ abstract class AnnotationsScanner {
boolean calledProcessor = false; boolean calledProcessor = false;
if (sourceClass == rootMethod.getDeclaringClass()) { if (sourceClass == rootMethod.getDeclaringClass()) {
result = processMethodAnnotations(context, aggregateIndex[0], result = processMethodAnnotations(context, aggregateIndex[0],
rootMethod, processor, classFilter); rootMethod, processor);
calledProcessor = true; calledProcessor = true;
if (result != null) { if (result != null) {
return result; return result;
} }
} }
else { else {
for (Method candidateMethod : getBaseTypeMethods(context, sourceClass, classFilter)) { for (Method candidateMethod : getBaseTypeMethods(context, sourceClass)) {
if (candidateMethod != null && isOverride(rootMethod, candidateMethod)) { if (candidateMethod != null && isOverride(rootMethod, candidateMethod)) {
result = processMethodAnnotations(context, aggregateIndex[0], result = processMethodAnnotations(context, aggregateIndex[0],
candidateMethod, processor, classFilter); candidateMethod, processor);
calledProcessor = true; calledProcessor = true;
if (result != null) { if (result != null) {
return result; return result;
@ -344,7 +311,7 @@ abstract class AnnotationsScanner {
if (includeInterfaces) { if (includeInterfaces) {
for (Class<?> interfaceType : sourceClass.getInterfaces()) { for (Class<?> interfaceType : sourceClass.getInterfaces()) {
R interfacesResult = processMethodHierarchy(context, aggregateIndex, R interfacesResult = processMethodHierarchy(context, aggregateIndex,
interfaceType, processor, classFilter, rootMethod, true); interfaceType, processor, rootMethod, true);
if (interfacesResult != null) { if (interfacesResult != null) {
return interfacesResult; return interfacesResult;
} }
@ -353,7 +320,7 @@ abstract class AnnotationsScanner {
Class<?> superclass = sourceClass.getSuperclass(); Class<?> superclass = sourceClass.getSuperclass();
if (superclass != Object.class && superclass != null) { if (superclass != Object.class && superclass != null) {
R superclassResult = processMethodHierarchy(context, aggregateIndex, R superclassResult = processMethodHierarchy(context, aggregateIndex,
superclass, processor, classFilter, rootMethod, includeInterfaces); superclass, processor, rootMethod, includeInterfaces);
if (superclassResult != null) { if (superclassResult != null) {
return superclassResult; return superclassResult;
} }
@ -365,11 +332,8 @@ abstract class AnnotationsScanner {
return null; return null;
} }
private static <C> Method[] getBaseTypeMethods( private static <C> Method[] getBaseTypeMethods(C context, Class<?> baseType) {
C context, Class<?> baseType, @Nullable BiPredicate<C, Class<?>> classFilter) { if (baseType == Object.class || hasPlainJavaAnnotationsOnly(baseType)) {
if (baseType == Object.class || hasPlainJavaAnnotationsOnly(baseType) ||
isFiltered(baseType, context, classFilter)) {
return NO_METHODS; return NO_METHODS;
} }
@ -433,16 +397,16 @@ abstract class AnnotationsScanner {
@Nullable @Nullable
private static <C, R> R processMethodAnnotations(C context, int aggregateIndex, Method source, 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); R result = processor.doWithAnnotations(context, aggregateIndex, source, annotations);
if (result != null) { if (result != null) {
return result; return result;
} }
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(source); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(source);
if (bridgedMethod != source) { if (bridgedMethod != source) {
Annotation[] bridgedAnnotations = getDeclaredAnnotations(context, bridgedMethod, classFilter, true); Annotation[] bridgedAnnotations = getDeclaredAnnotations(bridgedMethod, true);
for (int i = 0; i < bridgedAnnotations.length; i++) { for (int i = 0; i < bridgedAnnotations.length; i++) {
if (ObjectUtils.containsElement(annotations, bridgedAnnotations[i])) { if (ObjectUtils.containsElement(annotations, bridgedAnnotations[i])) {
bridgedAnnotations[i] = null; bridgedAnnotations[i] = null;
@ -455,12 +419,12 @@ abstract class AnnotationsScanner {
@Nullable @Nullable
private static <C, R> R processElement(C context, AnnotatedElement source, private static <C, R> R processElement(C context, AnnotatedElement source,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) { AnnotationsProcessor<C, R> processor) {
try { try {
R result = processor.doWithAggregate(context, 0); R result = processor.doWithAggregate(context, 0);
return (result != null ? result : processor.doWithAnnotations( return (result != null ? result : processor.doWithAnnotations(
context, 0, source, getDeclaredAnnotations(context, source, classFilter, false))); context, 0, source, getDeclaredAnnotations(source, false)));
} }
catch (Throwable ex) { catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex); AnnotationUtils.handleIntrospectionFailure(source, ex);
@ -468,18 +432,6 @@ abstract class AnnotationsScanner {
return null; 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") @SuppressWarnings("unchecked")
@Nullable @Nullable
static <A extends Annotation> A getDeclaredAnnotation(AnnotatedElement source, Class<A> annotationType) { static <A extends Annotation> A getDeclaredAnnotation(AnnotatedElement source, Class<A> annotationType) {
@ -525,12 +477,6 @@ abstract class AnnotationsScanner {
return annotations.clone(); 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) { private static boolean isIgnorable(Class<?> annotationType) {
return AnnotationFilter.PLAIN.matches(annotationType); return AnnotationFilter.PLAIN.matches(annotationType);
} }

45
spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java

@ -128,51 +128,6 @@ class AnnotationsScannerTests {
assertThat(scan(source, SearchStrategy.INHERITED_ANNOTATIONS)).containsExactly("0:TestInheritedAnnotation2"); 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 @Test
void superclassStrategyOnClassWhenNotAnnotatedScansNone() { void superclassStrategyOnClassWhenNotAnnotatedScansNone() {
Class<?> source = WithNoAnnotations.class; Class<?> source = WithNoAnnotations.class;

Loading…
Cancel
Save