Skip to content

Commit fd809cd

Browse files
committed
AnnotationUtils defensively catches unexpected exceptions from retrieval attempts (proceeding like the annotation wasn't there)
This is analogous to what the JVM does for cases where the annotation type itself isn't present on the classpath. We're effectively extending that policy to values referenced within an annotation declaration. Issue: SPR-11874
1 parent f1517f0 commit fd809cd

File tree

1 file changed

+71
-25
lines changed

1 file changed

+71
-25
lines changed

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

+71-25
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,14 @@ public static <T extends Annotation> T getAnnotation(Annotation ann, Class<T> an
7979
if (annotationType.isInstance(ann)) {
8080
return (T) ann;
8181
}
82-
return ann.annotationType().getAnnotation(annotationType);
82+
try {
83+
return ann.annotationType().getAnnotation(annotationType);
84+
}
85+
catch (Exception ex) {
86+
// Assuming nested Class values not resolvable within annotation attributes...
87+
// We're probably hitting a non-present optional arrangement - let's back out.
88+
return null;
89+
}
8390
}
8491

8592
/**
@@ -92,16 +99,23 @@ public static <T extends Annotation> T getAnnotation(Annotation ann, Class<T> an
9299
* @since 3.1
93100
*/
94101
public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<T> annotationType) {
95-
T ann = ae.getAnnotation(annotationType);
96-
if (ann == null) {
97-
for (Annotation metaAnn : ae.getAnnotations()) {
98-
ann = metaAnn.annotationType().getAnnotation(annotationType);
99-
if (ann != null) {
100-
break;
102+
try {
103+
T ann = ae.getAnnotation(annotationType);
104+
if (ann == null) {
105+
for (Annotation metaAnn : ae.getAnnotations()) {
106+
ann = metaAnn.annotationType().getAnnotation(annotationType);
107+
if (ann != null) {
108+
break;
109+
}
101110
}
102111
}
112+
return ann;
113+
}
114+
catch (Exception ex) {
115+
// Assuming nested Class values not resolvable within annotation attributes...
116+
// We're probably hitting a non-present optional arrangement - let's back out.
117+
return null;
103118
}
104-
return ann;
105119
}
106120

107121
/**
@@ -112,7 +126,14 @@ public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<
112126
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
113127
*/
114128
public static Annotation[] getAnnotations(Method method) {
115-
return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
129+
try {
130+
return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
131+
}
132+
catch (Exception ex) {
133+
// Assuming nested Class values not resolvable within annotation attributes...
134+
// We're probably hitting a non-present optional arrangement - let's back out.
135+
return null;
136+
}
116137
}
117138

118139
/**
@@ -162,10 +183,16 @@ public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method metho
162183
public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
163184
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
164185

165-
if (annotatedElement.getAnnotations().length == 0) {
166-
return Collections.emptySet();
186+
try {
187+
if (annotatedElement.getAnnotations().length > 0) {
188+
return new AnnotationCollector<A>(containerAnnotationType, annotationType).getResult(annotatedElement);
189+
}
167190
}
168-
return new AnnotationCollector<A>(containerAnnotationType, annotationType).getResult(annotatedElement);
191+
catch (Exception ex) {
192+
// Assuming nested Class values not resolvable within annotation attributes...
193+
// We're probably hitting a non-present optional arrangement - let's back out.
194+
}
195+
return Collections.emptySet();
169196
}
170197

171198
/**
@@ -230,9 +257,15 @@ private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
230257
}
231258
boolean found = false;
232259
for (Method ifcMethod : iface.getMethods()) {
233-
if (ifcMethod.getAnnotations().length > 0) {
234-
found = true;
235-
break;
260+
try {
261+
if (ifcMethod.getAnnotations().length > 0) {
262+
found = true;
263+
break;
264+
}
265+
}
266+
catch (Exception ex) {
267+
// Assuming nested Class values not resolvable within annotation attributes...
268+
// We're probably hitting a non-present optional arrangement - let's back out.
236269
}
237270
}
238271
annotatedInterfaceCache.put(iface, found);
@@ -278,7 +311,14 @@ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> a
278311
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
279312
Assert.notNull(clazz, "Class must not be null");
280313
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
281-
return clazz.getAnnotation(annotationType);
314+
try {
315+
return clazz.getAnnotation(annotationType);
316+
}
317+
catch (Exception ex) {
318+
// Assuming nested Class values not resolvable within annotation attributes...
319+
// We're probably hitting a non-present optional arrangement - let's back out.
320+
return null;
321+
}
282322
}
283323
for (Class<?> ifc : clazz.getInterfaces()) {
284324
A annotation = findAnnotation(ifc, annotationType, visited);
@@ -390,12 +430,18 @@ public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> an
390430
Assert.notNull(annotationType, "Annotation type must not be null");
391431
Assert.notNull(clazz, "Class must not be null");
392432
boolean declaredLocally = false;
393-
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
394-
if (annotation.annotationType().equals(annotationType)) {
395-
declaredLocally = true;
396-
break;
433+
try {
434+
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
435+
if (annotation.annotationType().equals(annotationType)) {
436+
declaredLocally = true;
437+
break;
438+
}
397439
}
398440
}
441+
catch (Exception ex) {
442+
// Assuming nested Class values not resolvable within annotation attributes...
443+
// We're probably hitting a non-present optional arrangement - let's back out.
444+
}
399445
return declaredLocally;
400446
}
401447

@@ -632,7 +678,7 @@ private void process(AnnotatedElement annotatedElement) {
632678
this.result.add((A) annotation);
633679
}
634680
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, annotation.annotationType())) {
635-
this.result.addAll(Arrays.asList(getValue(annotation)));
681+
this.result.addAll(getValue(annotation));
636682
}
637683
else if (!isInJavaLangAnnotationPackage(annotation)) {
638684
process(annotation.annotationType());
@@ -642,15 +688,15 @@ else if (!isInJavaLangAnnotationPackage(annotation)) {
642688
}
643689

644690
@SuppressWarnings("unchecked")
645-
private A[] getValue(Annotation annotation) {
691+
private List<A> getValue(Annotation annotation) {
646692
try {
647693
Method method = annotation.annotationType().getDeclaredMethod("value");
648694
ReflectionUtils.makeAccessible(method);
649-
return (A[]) method.invoke(annotation);
695+
return Arrays.asList((A[]) method.invoke(annotation));
650696
}
651697
catch (Exception ex) {
652-
throw new IllegalStateException("Unable to read value from repeating annotation container " +
653-
this.containerAnnotationType.getName(), ex);
698+
// Unable to read value from repeating annotation container -> ignore it.
699+
return Collections.emptyList();
654700
}
655701
}
656702
}

0 commit comments

Comments
 (0)