From 6e21b19999e967e4f4933bfda10b7a85206def34 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 10 Dec 2019 22:38:55 +0100 Subject: [PATCH] Make TYPE_HIERARCHY_AND_ENCLOSING_CLASSES annotation search strategy defensive Prior to this commit, when searching for annotations using the TYPE_HIERARCHY_AND_ENCLOSING_CLASSES strategy an exception could be thrown while attempting to load the enclosing class (e.g., a NoClassDefFoundError), thereby halting the entire annotation scanning process. This commit makes this search strategy defensive by logging exceptions encountered while processing the enclosing class hierarchy instead of allowing the exception to halt the entire annotation scanning process. The exception handling is performed by AnnotationUtils.handleIntrospectionFailure() which only allows an AnnotationConfigurationException to propagate. See gh-24136 --- .../core/annotation/AnnotationUtils.java | 9 ++++---- .../core/annotation/AnnotationsScanner.java | 22 ++++++++++++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index f27e81ac80..f80d0c7c33 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -1087,16 +1087,17 @@ public abstract class AnnotationUtils { *

If the supplied exception is an {@link AnnotationConfigurationException}, * it will simply be thrown, allowing it to propagate to the caller, and * nothing will be logged. - *

Otherwise, this method logs an introspection failure (in particular - * {@code TypeNotPresentExceptions}) before moving on, assuming nested - * Class values were not resolvable within annotation attributes and + *

Otherwise, this method logs an introspection failure (in particular for + * a {@link TypeNotPresentException}) before moving on, assuming nested + * {@code Class} values were not resolvable within annotation attributes and * thereby effectively pretending there were no annotations on the specified * element. * @param element the element that we tried to introspect annotations on * @param ex the exception that we encountered * @see #rethrowAnnotationConfigurationException + * @see IntrospectionFailureLogger */ - private static void handleIntrospectionFailure(@Nullable AnnotatedElement element, Throwable ex) { + static void handleIntrospectionFailure(@Nullable AnnotatedElement element, Throwable ex) { rethrowAnnotationConfigurationException(ex); IntrospectionFailureLogger logger = IntrospectionFailureLogger.INFO; boolean meta = false; diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java index c41a67b73d..33c1ce305c 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java @@ -231,14 +231,24 @@ abstract class AnnotationsScanner { } } if (includeEnclosing) { - Class enclosingClass = source.getEnclosingClass(); - if (enclosingClass != null) { - R enclosingResult = processClassHierarchy(context, aggregateIndex, - enclosingClass, processor, classFilter, includeInterfaces, true); - if (enclosingResult != null) { - return enclosingResult; + // Since merely attempting to load the enclosing class may result in + // automatic loading of sibling nested classes that in turn results + // in an exception such as NoClassDefFoundError, we wrap the following + // in its own dedicated try-catch block in order not to preemptively + // halt the annotation scanning process. + try { + Class enclosingClass = source.getEnclosingClass(); + if (enclosingClass != null) { + R enclosingResult = processClassHierarchy(context, aggregateIndex, + enclosingClass, processor, classFilter, includeInterfaces, true); + if (enclosingResult != null) { + return enclosingResult; + } } } + catch (Throwable ex) { + AnnotationUtils.handleIntrospectionFailure(source, ex); + } } return null; }