Fix bug in TYPE_HIERARCHY_AND_ENCLOSING_CLASSES strategy

Prior to this commit, the new `TYPE_HIERARCHY_AND_ENCLOSING_CLASSES`
annotation search strategy failed to find annotations on enclosing
classes if the source class was a nested class that itself had no
annotations present.

This commit fixes this by adding special logic to AnnotationsScanner's
isWithoutHierarchy() method to properly support nested classes.

Closes gh-23378
This commit is contained in:
Sam Brannen 2019-07-31 22:05:46 +02:00
parent b03dd47598
commit de3c115614
2 changed files with 35 additions and 7 deletions

View File

@ -39,6 +39,7 @@ import org.springframework.util.ReflectionUtils;
* {@link AnnotatedElement}.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
* @see AnnotationsProcessor
*/
@ -121,7 +122,7 @@ abstract class AnnotationsScanner {
case DIRECT:
return processElement(context, source, processor, classFilter);
case INHERITED_ANNOTATIONS:
return processClassInheritedAnnotations(context, source, processor, classFilter);
return processClassInheritedAnnotations(context, source, searchStrategy, processor, classFilter);
case SUPERCLASS:
return processClassHierarchy(context, source, processor, classFilter, false, false);
case EXHAUSTIVE:
@ -135,9 +136,9 @@ abstract class AnnotationsScanner {
@Nullable
private static <C, R> R processClassInheritedAnnotations(C context, Class<?> source,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
if (isWithoutHierarchy(source)) {
if (isWithoutHierarchy(source, searchStrategy)) {
return processElement(context, source, processor, classFilter);
}
Annotation[] relevant = null;
@ -505,7 +506,7 @@ abstract class AnnotationsScanner {
if (hasPlainJavaAnnotationsOnly(source)) {
return true;
}
if (searchStrategy == SearchStrategy.DIRECT || isWithoutHierarchy(source)) {
if (searchStrategy == SearchStrategy.DIRECT || isWithoutHierarchy(source, searchStrategy)) {
if (source instanceof Method && ((Method) source).isBridge()) {
return false;
}
@ -530,19 +531,21 @@ abstract class AnnotationsScanner {
return (type.getName().startsWith("java.") || type == Ordered.class);
}
private static boolean isWithoutHierarchy(AnnotatedElement source) {
private static boolean isWithoutHierarchy(AnnotatedElement source, SearchStrategy searchStrategy) {
if (source == Object.class) {
return true;
}
if (source instanceof Class) {
Class<?> sourceClass = (Class<?>) source;
return (sourceClass.getSuperclass() == Object.class &&
boolean noSuperTypes = (sourceClass.getSuperclass() == Object.class &&
sourceClass.getInterfaces().length == 0);
return (searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes &&
sourceClass.getEnclosingClass() == null : noSuperTypes);
}
if (source instanceof Method) {
Method sourceMethod = (Method) source;
return (Modifier.isPrivate(sourceMethod.getModifiers()) ||
isWithoutHierarchy(sourceMethod.getDeclaringClass()));
isWithoutHierarchy(sourceMethod.getDeclaringClass(), searchStrategy));
}
return true;
}

View File

@ -692,6 +692,19 @@ public class MergedAnnotationsTests {
Transactional.class)).hasSize(1);
}
@Test
public void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedInnerClassWithAnnotatedEnclosingClass() {
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedInnerClass.class,
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
assertThat(classes).containsExactly(Component.class, Indexed.class);
}
@Test
public void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedStaticNestedClassWithAnnotatedEnclosingClass() {
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedStaticNestedClass.class,
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
assertThat(classes).containsExactly(Component.class, Indexed.class);
}
@Test
public void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
Method method = Leaf.class.getMethod("annotatedOnLeaf");
@ -2112,6 +2125,16 @@ public class MergedAnnotationsTests {
static class NonAnnotatedClass {
}
@Component
static class AnnotatedClass {
class NonAnnotatedInnerClass {
}
static class NonAnnotatedStaticNestedClass {
}
}
static interface NonAnnotatedInterface {
}
@ -2839,6 +2862,7 @@ public class MergedAnnotationsTests {
public static class ImplementsInterfaceWithGenericAnnotatedMethod
implements InterfaceWithGenericAnnotatedMethod<String> {
@Override
public void foo(String t) {
}
}
@ -2852,6 +2876,7 @@ public class MergedAnnotationsTests {
public static class ExtendsBaseClassWithGenericAnnotatedMethod
extends BaseClassWithGenericAnnotatedMethod<String> {
@Override
public void foo(String t) {
}
}