Skip to content

Commit 74c878e

Browse files
committed
AnnotationUtils defensively catches and logs unexpected exceptions from retrieval attempts (proceeding like the annotation wasn't there)
Issue: SPR-11874 (cherry picked from commit 2c0c081)
1 parent 178d58c commit 74c878e

File tree

1 file changed

+100
-28
lines changed

1 file changed

+100
-28
lines changed

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

+100-28
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
import java.util.Set;
2929
import java.util.WeakHashMap;
3030

31+
import org.apache.commons.logging.Log;
32+
import org.apache.commons.logging.LogFactory;
33+
3134
import org.springframework.core.BridgeMethodResolver;
3235
import org.springframework.util.Assert;
3336
import org.springframework.util.ObjectUtils;
@@ -63,6 +66,8 @@ public abstract class AnnotationUtils {
6366
/** The attribute name for annotations with a single element */
6467
public static final String VALUE = "value";
6568

69+
private static final Log logger = LogFactory.getLog(AnnotationUtils.class);
70+
6671
private static final Map<Class<?>, Boolean> annotatedInterfaceCache = new WeakHashMap<Class<?>, Boolean>();
6772

6873

@@ -79,29 +84,49 @@ public static <T extends Annotation> T getAnnotation(Annotation ann, Class<T> an
7984
if (annotationType.isInstance(ann)) {
8085
return (T) ann;
8186
}
82-
return ann.annotationType().getAnnotation(annotationType);
87+
try {
88+
return ann.annotationType().getAnnotation(annotationType);
89+
}
90+
catch (Exception ex) {
91+
// Assuming nested Class values not resolvable within annotation attributes...
92+
// We're probably hitting a non-present optional arrangement - let's back out.
93+
if (logger.isInfoEnabled()) {
94+
logger.info("Failed to introspect annotations on [" + ann.annotationType() + "]: " + ex);
95+
}
96+
return null;
97+
}
8398
}
8499

85100
/**
86101
* Get a single {@link Annotation} of {@code annotationType} from the supplied
87102
* Method, Constructor or Field. Meta-annotations will be searched if the annotation
88103
* is not declared locally on the supplied element.
89-
* @param ae the Method, Constructor or Field from which to get the annotation
104+
* @param annotatedElement the Method, Constructor or Field from which to get the annotation
90105
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
91106
* @return the matching annotation, or {@code null} if none found
92107
* @since 3.1
93108
*/
94-
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;
109+
public static <T extends Annotation> T getAnnotation(AnnotatedElement annotatedElement, Class<T> annotationType) {
110+
try {
111+
T ann = annotatedElement.getAnnotation(annotationType);
112+
if (ann == null) {
113+
for (Annotation metaAnn : annotatedElement.getAnnotations()) {
114+
ann = metaAnn.annotationType().getAnnotation(annotationType);
115+
if (ann != null) {
116+
break;
117+
}
101118
}
102119
}
120+
return ann;
121+
}
122+
catch (Exception ex) {
123+
// Assuming nested Class values not resolvable within annotation attributes...
124+
// We're probably hitting a non-present optional arrangement - let's back out.
125+
if (logger.isInfoEnabled()) {
126+
logger.info("Failed to introspect annotations on [" + annotatedElement + "]: " + ex);
127+
}
128+
return null;
103129
}
104-
return ann;
105130
}
106131

107132
/**
@@ -112,7 +137,17 @@ public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<
112137
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
113138
*/
114139
public static Annotation[] getAnnotations(Method method) {
115-
return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
140+
try {
141+
return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
142+
}
143+
catch (Exception ex) {
144+
// Assuming nested Class values not resolvable within annotation attributes...
145+
// We're probably hitting a non-present optional arrangement - let's back out.
146+
if (logger.isInfoEnabled()) {
147+
logger.info("Failed to introspect annotations on [" + method + "]: " + ex);
148+
}
149+
return null;
150+
}
116151
}
117152

118153
/**
@@ -162,10 +197,19 @@ public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method metho
162197
public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
163198
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
164199

165-
if (annotatedElement.getAnnotations().length == 0) {
166-
return Collections.emptySet();
200+
try {
201+
if (annotatedElement.getAnnotations().length > 0) {
202+
return new AnnotationCollector<A>(containerAnnotationType, annotationType).getResult(annotatedElement);
203+
}
204+
}
205+
catch (Exception ex) {
206+
// Assuming nested Class values not resolvable within annotation attributes...
207+
// We're probably hitting a non-present optional arrangement - let's back out.
208+
if (logger.isInfoEnabled()) {
209+
logger.info("Failed to introspect annotations on [" + annotatedElement + "]: " + ex);
210+
}
167211
}
168-
return new AnnotationCollector<A>(containerAnnotationType, annotationType).getResult(annotatedElement);
212+
return Collections.emptySet();
169213
}
170214

171215
/**
@@ -230,9 +274,18 @@ private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
230274
}
231275
boolean found = false;
232276
for (Method ifcMethod : iface.getMethods()) {
233-
if (ifcMethod.getAnnotations().length > 0) {
234-
found = true;
235-
break;
277+
try {
278+
if (ifcMethod.getAnnotations().length > 0) {
279+
found = true;
280+
break;
281+
}
282+
}
283+
catch (Exception ex) {
284+
// Assuming nested Class values not resolvable within annotation attributes...
285+
// We're probably hitting a non-present optional arrangement - let's back out.
286+
if (logger.isInfoEnabled()) {
287+
logger.info("Failed to introspect annotations on [" + ifcMethod + "]: " + ex);
288+
}
236289
}
237290
}
238291
annotatedInterfaceCache.put(iface, found);
@@ -278,7 +331,17 @@ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> a
278331
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
279332
Assert.notNull(clazz, "Class must not be null");
280333
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
281-
return clazz.getAnnotation(annotationType);
334+
try {
335+
return clazz.getAnnotation(annotationType);
336+
}
337+
catch (Exception ex) {
338+
// Assuming nested Class values not resolvable within annotation attributes...
339+
// We're probably hitting a non-present optional arrangement - let's back out.
340+
if (logger.isInfoEnabled()) {
341+
logger.info("Failed to introspect annotations on [" + clazz + "]: " + ex);
342+
}
343+
return null;
344+
}
282345
}
283346
for (Class<?> ifc : clazz.getInterfaces()) {
284347
A annotation = findAnnotation(ifc, annotationType, visited);
@@ -390,10 +453,19 @@ public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> an
390453
Assert.notNull(annotationType, "Annotation type must not be null");
391454
Assert.notNull(clazz, "Class must not be null");
392455
boolean declaredLocally = false;
393-
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
394-
if (annotation.annotationType().equals(annotationType)) {
395-
declaredLocally = true;
396-
break;
456+
try {
457+
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
458+
if (annotation.annotationType().equals(annotationType)) {
459+
declaredLocally = true;
460+
break;
461+
}
462+
}
463+
}
464+
catch (Exception ex) {
465+
// Assuming nested Class values not resolvable within annotation attributes...
466+
// We're probably hitting a non-present optional arrangement - let's back out.
467+
if (logger.isInfoEnabled()) {
468+
logger.info("Failed to introspect annotations on [" + clazz + "]: " + ex);
397469
}
398470
}
399471
return declaredLocally;
@@ -502,7 +574,7 @@ else if (value instanceof Class[]) {
502574
}
503575
if (nestedAnnotationsAsMap && value instanceof Annotation) {
504576
attrs.put(method.getName(),
505-
getAnnotationAttributes((Annotation) value, classValuesAsString, true));
577+
getAnnotationAttributes((Annotation) value, classValuesAsString, true));
506578
}
507579
else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
508580
Annotation[] realAnnotations = (Annotation[]) value;
@@ -632,7 +704,7 @@ private void process(AnnotatedElement annotatedElement) {
632704
this.result.add((A) annotation);
633705
}
634706
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, annotation.annotationType())) {
635-
this.result.addAll(Arrays.asList(getValue(annotation)));
707+
this.result.addAll(getValue(annotation));
636708
}
637709
else if (!isInJavaLangAnnotationPackage(annotation)) {
638710
process(annotation.annotationType());
@@ -642,15 +714,15 @@ else if (!isInJavaLangAnnotationPackage(annotation)) {
642714
}
643715

644716
@SuppressWarnings("unchecked")
645-
private A[] getValue(Annotation annotation) {
717+
private List<A> getValue(Annotation annotation) {
646718
try {
647719
Method method = annotation.annotationType().getDeclaredMethod("value");
648720
ReflectionUtils.makeAccessible(method);
649-
return (A[]) method.invoke(annotation);
721+
return Arrays.asList((A[]) method.invoke(annotation));
650722
}
651723
catch (Exception ex) {
652-
throw new IllegalStateException("Unable to read value from repeating annotation container " +
653-
this.containerAnnotationType.getName(), ex);
724+
// Unable to read value from repeating annotation container -> ignore it.
725+
return Collections.emptyList();
654726
}
655727
}
656728
}

0 commit comments

Comments
 (0)