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
This commit is contained in:
Sam Brannen
2019-12-10 22:38:55 +01:00
parent 16ed7e2a19
commit 6e21b19999
2 changed files with 21 additions and 10 deletions

View File

@@ -1087,16 +1087,17 @@ public abstract class AnnotationUtils {
* <p>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.
* <p>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
* <p>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;

View File

@@ -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;
}