Skip to content

Commit 62d09be

Browse files
committed
Log warning if meta-annotation is ignored due to types not present
Prior to this commit, if a meta-annotation could not be loaded because its attributes referenced types not present in the classpath, the meta-annotation was silently ignored. To improve diagnostics for such use cases, this commit introduces WARN support in IntrospectionFailureLogger and revises AttributeMethods.canLoad() to log a warning if a meta-annotation is ignored due to an exception thrown while attempting to load its attributes. For example, a warning similar to the following is now logged in such cases. WARN o.s.c.a.MergedAnnotation - Failed to introspect meta-annotation @example.MyAnnotation on class example.Config: java.lang.TypeNotPresentException: Type example.OptionalDependency not present This commit also improves log messages in AnnotationTypeMappings. Closes gh-35927
1 parent 47f65b3 commit 62d09be

File tree

5 files changed

+31
-11
lines changed

5 files changed

+31
-11
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private AnnotationTypeMappings(RepeatableContainers repeatableContainers,
7979
private void addAllMappings(Class<? extends Annotation> annotationType,
8080
Set<Class<? extends Annotation>> visitedAnnotationTypes) {
8181
Deque<AnnotationTypeMapping> queue = new ArrayDeque<>();
82-
addIfPossible(queue, null, annotationType, null, visitedAnnotationTypes);
82+
addIfPossible(queue, null, annotationType, null, false, visitedAnnotationTypes);
8383
while (!queue.isEmpty()) {
8484
AnnotationTypeMapping mapping = queue.removeFirst();
8585
this.mappings.add(mapping);
@@ -109,21 +109,21 @@ private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, Annot
109109
}
110110

111111
private void addIfPossible(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source, Annotation ann) {
112-
addIfPossible(queue, source, ann.annotationType(), ann, new HashSet<>());
112+
addIfPossible(queue, source, ann.annotationType(), ann, true, new HashSet<>());
113113
}
114114

115115
private void addIfPossible(Deque<AnnotationTypeMapping> queue, @Nullable AnnotationTypeMapping source,
116116
Class<? extends Annotation> annotationType, @Nullable Annotation ann,
117-
Set<Class<? extends Annotation>> visitedAnnotationTypes) {
117+
boolean meta, Set<Class<? extends Annotation>> visitedAnnotationTypes) {
118118

119119
try {
120120
queue.addLast(new AnnotationTypeMapping(source, annotationType, ann, visitedAnnotationTypes));
121121
}
122122
catch (Exception ex) {
123123
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
124124
if (failureLogger.isEnabled()) {
125-
failureLogger.log("Failed to introspect meta-annotation " + annotationType.getName(),
126-
(source != null ? source.getAnnotationType() : null), ex);
125+
failureLogger.log("Failed to introspect " + (meta ? "meta-annotation @" : "annotation @") +
126+
annotationType.getName(), (source != null ? source.getAnnotationType() : null), ex);
127127
}
128128
}
129129
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ private static boolean hasSameGenericTypeParameters(
443443
Annotation annotation = annotations[i];
444444
//noinspection DataFlowIssue
445445
if (isIgnorable(annotation.annotationType()) ||
446-
!AttributeMethods.forAnnotationType(annotation.annotationType()).canLoad(annotation)) {
446+
!AttributeMethods.forAnnotationType(annotation.annotationType()).canLoad(annotation, source)) {
447447
annotations[i] = null;
448448
}
449449
else {

spring-core/src/main/java/org/springframework/core/annotation/AttributeMethods.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.core.annotation;
1818

1919
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.AnnotatedElement;
2021
import java.lang.reflect.Method;
2122
import java.util.Arrays;
2223
import java.util.Comparator;
@@ -38,6 +39,8 @@
3839
*/
3940
final class AttributeMethods {
4041

42+
private static final IntrospectionFailureLogger failureLogger = IntrospectionFailureLogger.WARN;
43+
4144
static final AttributeMethods NONE = new AttributeMethods(null, new Method[0]);
4245

4346
static final Map<Class<? extends Annotation>, AttributeMethods> cache = new ConcurrentReferenceHashMap<>();
@@ -91,10 +94,11 @@ private AttributeMethods(@Nullable Class<? extends Annotation> annotationType, M
9194
* exceptions for {@code Class} values (instead of the more typical early
9295
* {@code Class.getAnnotations() failure} on a regular JVM).
9396
* @param annotation the annotation to check
97+
* @param source the element that the supplied annotation is declared on
9498
* @return {@code true} if all values are present
9599
* @see #validate(Annotation)
96100
*/
97-
boolean canLoad(Annotation annotation) {
101+
boolean canLoad(Annotation annotation, AnnotatedElement source) {
98102
assertAnnotation(annotation);
99103
for (int i = 0; i < size(); i++) {
100104
if (canThrowTypeNotPresentException(i)) {
@@ -107,6 +111,10 @@ boolean canLoad(Annotation annotation) {
107111
}
108112
catch (Throwable ex) {
109113
// TypeNotPresentException etc. -> annotation type not actually loadable.
114+
if (failureLogger.isEnabled()) {
115+
failureLogger.log("Failed to introspect meta-annotation @" +
116+
getName(annotation.annotationType()), source, ex);
117+
}
110118
return false;
111119
}
112120
}

spring-core/src/main/java/org/springframework/core/annotation/IntrospectionFailureLogger.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
* Log facade used to handle annotation introspection failures (in particular
2525
* {@code TypeNotPresentExceptions}). Allows annotation processing to continue,
2626
* assuming that when Class attribute values are not resolvable the annotation
27-
* should effectively disappear.
27+
* should effectively be ignored.
2828
*
2929
* @author Phillip Webb
30+
* @author Sam Brannen
3031
* @since 5.2
3132
*/
3233
enum IntrospectionFailureLogger {
@@ -51,13 +52,24 @@ public boolean isEnabled() {
5152
public void log(String message) {
5253
getLogger().info(message);
5354
}
55+
},
56+
57+
WARN {
58+
@Override
59+
public boolean isEnabled() {
60+
return getLogger().isWarnEnabled();
61+
}
62+
@Override
63+
public void log(String message) {
64+
getLogger().warn(message);
65+
}
5466
};
5567

5668

5769
private static @Nullable Log logger;
5870

5971

60-
void log(String message, @Nullable Object source, Exception ex) {
72+
void log(String message, @Nullable Object source, Throwable ex) {
6173
String on = (source != null ? " on " + source : "");
6274
log(message + on + ": " + ex);
6375
}

spring-core/src/test/java/org/springframework/core/annotation/AttributeMethodsTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void isValidWhenHasTypeNotPresentExceptionReturnsFalse() {
112112
ClassValue annotation = mockAnnotation(ClassValue.class);
113113
given(annotation.value()).willThrow(TypeNotPresentException.class);
114114
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
115-
assertThat(attributes.canLoad(annotation)).isFalse();
115+
assertThat(attributes.canLoad(annotation, getClass())).isFalse();
116116
}
117117

118118
@Test
@@ -121,7 +121,7 @@ void isValidWhenDoesNotHaveTypeNotPresentExceptionReturnsTrue() {
121121
ClassValue annotation = mock();
122122
given(annotation.value()).willReturn((Class) InputStream.class);
123123
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
124-
assertThat(attributes.canLoad(annotation)).isTrue();
124+
assertThat(attributes.canLoad(annotation, getClass())).isTrue();
125125
}
126126

127127
@Test

0 commit comments

Comments
 (0)