AnnotationUtils.java 72.3 KB
Newer Older
A
Arjen Poutsma 已提交
1
/*
2
 * Copyright 2002-2015 the original author or authors.
A
Arjen Poutsma 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.core.annotation;

import java.lang.annotation.Annotation;
20
import java.lang.reflect.AnnotatedElement;
21
import java.lang.reflect.Array;
22 23
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
A
Arjen Poutsma 已提交
24
import java.lang.reflect.Method;
25 26
import java.lang.reflect.Proxy;
import java.util.ArrayList;
27
import java.util.Collections;
28
import java.util.HashMap;
29 30
import java.util.HashSet;
import java.util.LinkedHashSet;
31
import java.util.List;
A
Arjen Poutsma 已提交
32
import java.util.Map;
33
import java.util.Set;
A
Arjen Poutsma 已提交
34

35 36
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
S
Sam Brannen 已提交
37

A
Arjen Poutsma 已提交
38 39
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;
40
import org.springframework.util.ClassUtils;
41
import org.springframework.util.ConcurrentReferenceHashMap;
42
import org.springframework.util.ObjectUtils;
43
import org.springframework.util.ReflectionUtils;
44
import org.springframework.util.StringUtils;
A
Arjen Poutsma 已提交
45 46

/**
47 48 49 50 51 52
 * General utility methods for working with annotations, handling meta-annotations,
 * bridge methods (which the compiler generates for generic declarations) as well
 * as super methods (for optional <em>annotation inheritance</em>).
 *
 * <p>Note that most of the features of this class are not provided by the
 * JDK's introspection facilities themselves.
A
Arjen Poutsma 已提交
53
 *
S
Sam Brannen 已提交
54 55 56 57 58 59 60 61
 * <p>As a general rule for runtime-retained annotations (e.g. for transaction
 * control, authorization, or service exposure), always use the lookup methods
 * on this class (e.g., {@link #findAnnotation(Method, Class)},
 * {@link #getAnnotation(Method, Class)}, and {@link #getAnnotations(Method)})
 * instead of the plain annotation lookup methods in the JDK. You can still
 * explicitly choose between a <em>get</em> lookup on the given class level only
 * ({@link #getAnnotation(Method, Class)}) and a <em>find</em> lookup in the entire
 * inheritance hierarchy of the given method ({@link #findAnnotation(Method, Class)}).
A
Arjen Poutsma 已提交
62
 *
63
 * <h3>Terminology</h3>
64 65 66
 * The terms <em>directly present</em>, <em>indirectly present</em>, and
 * <em>present</em> have the same meanings as defined in the class-level
 * Javadoc for {@link AnnotatedElement} (in Java 8).
67 68 69 70 71
 *
 * <p>An annotation is <em>meta-present</em> on an element if the annotation
 * is declared as a meta-annotation on some other annotation which is
 * <em>present</em> on the element.
 *
72
 * <h3>Meta-annotation Support</h3>
73 74 75 76 77
 * <p>Most {@code find*()} methods and some {@code get*()} methods in this
 * class provide support for finding annotations used as meta-annotations.
 * Consult the Javadoc for each method in this class for details. For support
 * for meta-annotations with <em>attribute overrides</em> in
 * <em>composed annotations</em>, use {@link AnnotatedElementUtils} instead.
78
 *
79 80 81 82 83 84
 * <h3>Search Scope</h3>
 * <p>The search algorithms used by methods in this class stop searching for
 * an annotation once the first annotation of the specified type has been
 * found. As a consequence, additional annotations of the specified type will
 * be silently ignored.
 *
A
Arjen Poutsma 已提交
85 86 87 88
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @author Mark Fisher
C
Chris Beams 已提交
89
 * @author Chris Beams
90
 * @author Phillip Webb
A
Arjen Poutsma 已提交
91
 * @since 2.0
S
Sam Brannen 已提交
92 93 94 95
 * @see AliasFor
 * @see AnnotationAttributes
 * @see AnnotatedElementUtils
 * @see BridgeMethodResolver
96 97 98
 * @see java.lang.reflect.AnnotatedElement#getAnnotations()
 * @see java.lang.reflect.AnnotatedElement#getAnnotation(Class)
 * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotations()
A
Arjen Poutsma 已提交
99 100 101
 */
public abstract class AnnotationUtils {

102 103 104
	/**
	 * The attribute name for annotations with a single element.
	 */
105
	public static final String VALUE = "value";
A
Arjen Poutsma 已提交
106

107

108
	/**
S
Sam Brannen 已提交
109
	 * An object that can be stored in {@link AnnotationAttributes} as a
110 111
	 * placeholder for an attribute's declared default value.
	 */
112
	private static final Object DEFAULT_VALUE_PLACEHOLDER = new String("<SPRING DEFAULT VALUE PLACEHOLDER>");
113

114 115 116 117 118
	private static final Map<AnnotationCacheKey, Annotation> findAnnotationCache =
			new ConcurrentReferenceHashMap<AnnotationCacheKey, Annotation>(256);

	private static final Map<Class<?>, Boolean> annotatedInterfaceCache =
			new ConcurrentReferenceHashMap<Class<?>, Boolean>(256);
119

120 121 122
	private static final Map<Class<? extends Annotation>, Boolean> synthesizableCache =
			new ConcurrentReferenceHashMap<Class<? extends Annotation>, Boolean>(256);

S
Sam Brannen 已提交
123
	private static final Map<Class<? extends Annotation>, Map<String, String>> attributeAliasesCache =
124 125
			new ConcurrentReferenceHashMap<Class<? extends Annotation>, Map<String, String>>(256);

126 127 128
	private static final Map<Class<? extends Annotation>, List<Method>> attributeMethodsCache =
			new ConcurrentReferenceHashMap<Class<? extends Annotation>, List<Method>>(256);

129 130
	private static transient Log logger;

J
Juergen Hoeller 已提交
131

132 133
	/**
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied
134 135
	 * annotation: either the given annotation itself or a direct meta-annotation
	 * thereof.
136 137 138
	 * <p>Note that this method supports only a single level of meta-annotations.
	 * For support for arbitrary levels of meta-annotations, use one of the
	 * {@code find*()} methods instead.
139
	 * @param ann the Annotation to check
J
Juergen Hoeller 已提交
140
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
141
	 * @return the first matching annotation, or {@code null} if not found
142 143 144
	 * @since 4.0
	 */
	@SuppressWarnings("unchecked")
145
	public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> annotationType) {
146
		if (annotationType.isInstance(ann)) {
147
			return synthesizeAnnotation((A) ann);
148
		}
149
		Class<? extends Annotation> annotatedElement = ann.annotationType();
150
		try {
151
			return synthesizeAnnotation(annotatedElement.getAnnotation(annotationType), annotatedElement);
152 153
		}
		catch (Exception ex) {
154
			handleIntrospectionFailure(annotatedElement, ex);
155
		}
156
		return null;
157 158
	}

159
	/**
C
Chris Beams 已提交
160
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied
161 162
	 * {@link AnnotatedElement}, where the annotation is either <em>present</em> or
	 * <em>meta-present</em> on the {@code AnnotatedElement}.
163 164 165
	 * <p>Note that this method supports only a single level of meta-annotations.
	 * For support for arbitrary levels of meta-annotations, use
	 * {@link #findAnnotation(AnnotatedElement, Class)} instead.
166
	 * @param annotatedElement the {@code AnnotatedElement} from which to get the annotation
J
Juergen Hoeller 已提交
167
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
168
	 * @return the first matching annotation, or {@code null} if not found
C
Chris Beams 已提交
169
	 * @since 3.1
170
	 */
171
	public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
172
		try {
173 174
			A annotation = annotatedElement.getAnnotation(annotationType);
			if (annotation == null) {
175
				for (Annotation metaAnn : annotatedElement.getAnnotations()) {
176 177
					annotation = metaAnn.annotationType().getAnnotation(annotationType);
					if (annotation != null) {
178 179
						break;
					}
180 181
				}
			}
182
			return synthesizeAnnotation(annotation, annotatedElement);
183 184
		}
		catch (Exception ex) {
185
			handleIntrospectionFailure(annotatedElement, ex);
186
		}
187
		return null;
188 189
	}

190
	/**
191
	 * Get a single {@link Annotation} of {@code annotationType} from the
192 193
	 * supplied {@link Method}, where the annotation is either <em>present</em>
	 * or <em>meta-present</em> on the method.
194
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
195 196 197
	 * <p>Note that this method supports only a single level of meta-annotations.
	 * For support for arbitrary levels of meta-annotations, use
	 * {@link #findAnnotation(Method, Class)} instead.
198 199
	 * @param method the method to look for annotations on
	 * @param annotationType the annotation type to look for
200
	 * @return the first matching annotation, or {@code null} if not found
201 202 203 204 205 206 207 208 209 210 211 212
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
	 * @see #getAnnotation(AnnotatedElement, Class)
	 */
	public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
		Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
		return getAnnotation((AnnotatedElement) resolvedMethod, annotationType);
	}

	/**
	 * Get all {@link Annotation Annotations} that are <em>present</em> on the
	 * supplied {@link AnnotatedElement}.
	 * <p>Meta-annotations will <em>not</em> be searched.
213
	 * @param annotatedElement the Method, Constructor or Field to retrieve annotations from
214 215 216
	 * @return the annotations found, an empty array, or {@code null} if not
	 * resolvable (e.g. because nested Class values in annotation attributes
	 * failed to resolve at runtime)
217 218 219 220 221 222 223
	 * @since 4.0.8
	 */
	public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
		try {
			return annotatedElement.getAnnotations();
		}
		catch (Exception ex) {
224
			handleIntrospectionFailure(annotatedElement, ex);
225
		}
226
		return null;
227 228
	}

A
Arjen Poutsma 已提交
229
	/**
230 231
	 * Get all {@link Annotation Annotations} that are <em>present</em on the
	 * supplied {@link Method}.
A
Arjen Poutsma 已提交
232
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
233
	 * <p>Meta-annotations will <em>not</em> be searched.
234
	 * @param method the Method to retrieve annotations from
235 236 237
	 * @return the annotations found, an empty array, or {@code null} if not
	 * resolvable (e.g. because nested Class values in annotation attributes
	 * failed to resolve at runtime)
A
Arjen Poutsma 已提交
238
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
239
	 * @see AnnotatedElement#getAnnotations()
A
Arjen Poutsma 已提交
240 241
	 */
	public static Annotation[] getAnnotations(Method method) {
242 243 244 245
		try {
			return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
		}
		catch (Exception ex) {
246
			handleIntrospectionFailure(method, ex);
247
		}
248
		return null;
A
Arjen Poutsma 已提交
249 250 251
	}

	/**
252 253 254 255 256 257 258 259
	 * Delegates to {@link #getRepeatableAnnotations}.
	 * @since 4.0
	 * @deprecated As of Spring Framework 4.2, use {@link #getRepeatableAnnotations}
	 * or {@link #getDeclaredRepeatableAnnotations} instead.
	 */
	@Deprecated
	public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method method,
			Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
S
Sam Brannen 已提交
260
		return getRepeatableAnnotations(method, annotationType, containerAnnotationType);
261 262 263 264 265 266 267 268 269 270 271
	}

	/**
	 * Delegates to {@link #getRepeatableAnnotations}.
	 * @since 4.0
	 * @deprecated As of Spring Framework 4.2, use {@link #getRepeatableAnnotations}
	 * or {@link #getDeclaredRepeatableAnnotations} instead.
	 */
	@Deprecated
	public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
			Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
S
Sam Brannen 已提交
272
		return getRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType);
273 274 275 276 277 278 279 280 281 282
	}

	/**
	 * Get the <em>repeatable</em> {@linkplain Annotation annotations} of
	 * {@code annotationType} from the supplied {@link AnnotatedElement}, where
	 * such annotations are either <em>present</em> or <em>meta-present</em>
	 * on the element.
	 * <p>This method mimics the functionality of Java 8's
	 * {@link java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)}
	 * with additional support for meta-annotations.
283
	 * <p>Handles both single annotations and annotations nested within a
284 285 286
	 * <em>container annotation</em>.
	 * <p>Correctly handles <em>bridge methods</em> generated by the
	 * compiler if the supplied element is a {@link Method}.
287
	 * <p>Meta-annotations will be searched if the annotation is not
288 289
	 * <em>present</em> on the supplied element.
	 * @param annotatedElement the element to look for annotations on; never {@code null}
S
Sam Brannen 已提交
290
	 * @param annotationType the annotation type to look for; never {@code null}
291 292
	 * @param containerAnnotationType the type of the container that holds
	 * the annotations; may be {@code null} if a container is not supported
293
	 * @return the annotations found or an empty set; never {@code null}
294 295 296
	 * @since 4.2
	 * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class, Class)
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
297
	 * @see java.lang.annotation.Repeatable
298
	 * @see java.lang.reflect.AnnotatedElement#getAnnotationsByType
299
	 */
300
	public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
S
Sam Brannen 已提交
301
			Class<A> annotationType, Class<? extends Annotation> containerAnnotationType) {
J
Juergen Hoeller 已提交
302

S
Sam Brannen 已提交
303
		Set<A> annotations = getDeclaredRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType);
304 305 306 307
		if (!annotations.isEmpty()) {
			return annotations;
		}

S
Sam Brannen 已提交
308
		return getRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType, false);
309 310 311
	}

	/**
312 313 314 315 316 317 318
	 * Get the declared <em>repeatable</em> {@linkplain Annotation annotations}
	 * of {@code annotationType} from the supplied {@link AnnotatedElement},
	 * where such annotations are either <em>directly present</em>,
	 * <em>indirectly present</em>, or <em>meta-present</em> on the element.
	 * <p>This method mimics the functionality of Java 8's
	 * {@link java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType(Class)}
	 * with additional support for meta-annotations.
319
	 * <p>Handles both single annotations and annotations nested within a
320 321 322
	 * <em>container annotation</em>.
	 * <p>Correctly handles <em>bridge methods</em> generated by the
	 * compiler if the supplied element is a {@link Method}.
323
	 * <p>Meta-annotations will be searched if the annotation is not
324 325
	 * <em>present</em> on the supplied element.
	 * @param annotatedElement the element to look for annotations on; never {@code null}
S
Sam Brannen 已提交
326
	 * @param annotationType the annotation type to look for; never {@code null}
327 328
	 * @param containerAnnotationType the type of the container that holds
	 * the annotations; may be {@code null} if a container is not supported
329
	 * @return the annotations found or an empty set; never {@code null}
330 331 332
	 * @since 4.2
	 * @see #getRepeatableAnnotations(AnnotatedElement, Class, Class)
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
333
	 * @see java.lang.annotation.Repeatable
334
	 * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType
335
	 */
336
	public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(AnnotatedElement annotatedElement,
S
Sam Brannen 已提交
337 338
			Class<A> annotationType, Class<? extends Annotation> containerAnnotationType) {
		return getRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType, true);
339 340 341 342 343 344 345 346 347 348 349
	}

	/**
	 * Perform the actual work for {@link #getRepeatableAnnotations(AnnotatedElement, Class, Class)}
	 * and {@link #getDeclaredRepeatableAnnotations(AnnotatedElement, Class, Class)}.
	 * <p>Correctly handles <em>bridge methods</em> generated by the
	 * compiler if the supplied element is a {@link Method}.
	 * <p>Meta-annotations will be searched if the annotation is not
	 * <em>present</em> on the supplied element.
	 *
	 * @param annotatedElement the element to look for annotations on; never {@code null}
S
Sam Brannen 已提交
350
	 * @param annotationType the annotation type to look for; never {@code null}
351 352 353 354 355 356 357 358 359 360
	 * @param containerAnnotationType the type of the container that holds
	 * the annotations; may be {@code null} if a container is not supported
	 * @param declaredMode {@code true} if only declared annotations (i.e.,
	 * directly or indirectly present) should be considered.
	 * @return the annotations found or an empty set; never {@code null}
	 * @since 4.2
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
	 * @see java.lang.annotation.Repeatable
	 */
	private static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
S
Sam Brannen 已提交
361
			Class<A> annotationType, Class<? extends Annotation> containerAnnotationType, boolean declaredMode) {
362 363 364

		Assert.notNull(annotatedElement, "annotatedElement must not be null");
		Assert.notNull(annotationType, "annotationType must not be null");
J
Juergen Hoeller 已提交
365

366
		try {
367 368
			if (annotatedElement instanceof Method) {
				annotatedElement = BridgeMethodResolver.findBridgedMethod((Method) annotatedElement);
369
			}
S
Sam Brannen 已提交
370
			return new AnnotationCollector<A>(annotationType, containerAnnotationType, declaredMode).getResult(annotatedElement);
371
		}
372
		catch (Exception ex) {
373
			handleIntrospectionFailure(annotatedElement, ex);
374 375
		}
		return Collections.emptySet();
376 377
	}

A
Arjen Poutsma 已提交
378
	/**
379 380 381 382 383 384 385 386 387 388 389 390
	 * Find a single {@link Annotation} of {@code annotationType} on the
	 * supplied {@link AnnotatedElement}.
	 * <p>Meta-annotations will be searched if the annotation is not
	 * <em>directly present</em> on the supplied element.
	 * <p><strong>Warning</strong>: this method operates generically on
	 * annotated elements. In other words, this method does not execute
	 * specialized search algorithms for classes or methods. If you require
	 * the more specific semantics of {@link #findAnnotation(Class, Class)}
	 * or {@link #findAnnotation(Method, Class)}, invoke one of those methods
	 * instead.
	 * @param annotatedElement the {@code AnnotatedElement} on which to find the annotation
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
391
	 * @return the first matching annotation, or {@code null} if not found
392 393 394 395 396
	 * @since 4.2
	 */
	public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
		// Do NOT store result in the findAnnotationCache since doing so could break
		// findAnnotation(Class, Class) and findAnnotation(Method, Class).
397 398
		return synthesizeAnnotation(findAnnotation(annotatedElement, annotationType, new HashSet<Annotation>()),
			annotatedElement);
399 400 401 402 403 404 405 406 407
	}

	/**
	 * Perform the search algorithm for {@link #findAnnotation(AnnotatedElement, Class)}
	 * avoiding endless recursion by tracking which annotations have already
	 * been <em>visited</em>.
	 * @param annotatedElement the {@code AnnotatedElement} on which to find the annotation
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
	 * @param visited the set of annotations that have already been visited
408
	 * @return the first matching annotation, or {@code null} if not found
409 410 411
	 * @since 4.2
	 */
	@SuppressWarnings("unchecked")
412
	private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
413 414 415 416 417
		Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
		try {
			Annotation[] anns = annotatedElement.getDeclaredAnnotations();
			for (Annotation ann : anns) {
				if (ann.annotationType().equals(annotationType)) {
418
					return (A) ann;
419 420 421 422
				}
			}
			for (Annotation ann : anns) {
				if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
423
					A annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
424 425 426 427 428 429 430
					if (annotation != null) {
						return annotation;
					}
				}
			}
		}
		catch (Exception ex) {
431
			handleIntrospectionFailure(annotatedElement, ex);
432 433 434 435 436 437
		}
		return null;
	}

	/**
	 * Find a single {@link Annotation} of {@code annotationType} on the supplied
J
Juergen Hoeller 已提交
438
	 * {@link Method}, traversing its super methods (i.e., from superclasses and
439 440
	 * interfaces) if the annotation is not <em>directly present</em> on the given
	 * method itself.
441 442 443
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
	 * <p>Meta-annotations will be searched if the annotation is not
	 * <em>directly present</em> on the method.
S
Sam Brannen 已提交
444 445
	 * <p>Annotations on methods are not inherited by default, so we need to handle
	 * this explicitly.
A
Arjen Poutsma 已提交
446
	 * @param method the method to look for annotations on
J
Juergen Hoeller 已提交
447
	 * @param annotationType the annotation type to look for
448
	 * @return the first matching annotation, or {@code null} if not found
449
	 * @see #getAnnotation(Method, Class)
A
Arjen Poutsma 已提交
450
	 */
451
	@SuppressWarnings("unchecked")
A
Arjen Poutsma 已提交
452
	public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
453 454
		AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
		A result = (A) findAnnotationCache.get(cacheKey);
455

456
		if (result == null) {
457 458 459
			Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
			result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);

460
			if (result == null) {
461
				result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
A
Arjen Poutsma 已提交
462
			}
463 464

			Class<?> clazz = method.getDeclaringClass();
465 466
			while (result == null) {
				clazz = clazz.getSuperclass();
467
				if (clazz == null || Object.class == clazz) {
468 469 470 471
					break;
				}
				try {
					Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
472 473
					Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
					result = findAnnotation((AnnotatedElement) resolvedEquivalentMethod, annotationType);
474 475 476 477 478 479 480
				}
				catch (NoSuchMethodException ex) {
					// No equivalent method found
				}
				if (result == null) {
					result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
				}
481
			}
482

483 484 485
			if (result != null) {
				findAnnotationCache.put(cacheKey, result);
			}
A
Arjen Poutsma 已提交
486
		}
487

488
		return synthesizeAnnotation(result, method);
A
Arjen Poutsma 已提交
489 490
	}

491
	private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) {
492
		A annotation = null;
J
Juergen Hoeller 已提交
493
		for (Class<?> iface : ifcs) {
494 495 496 497 498 499 500 501 502 503 504
			if (isInterfaceWithAnnotatedMethods(iface)) {
				try {
					Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
					annotation = getAnnotation(equivalentMethod, annotationType);
				}
				catch (NoSuchMethodException ex) {
					// Skip this interface - it doesn't have the method...
				}
				if (annotation != null) {
					break;
				}
505
			}
506 507 508 509
		}
		return annotation;
	}

510
	static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
S
Sam Brannen 已提交
511 512 513
		Boolean found = annotatedInterfaceCache.get(iface);
		if (found != null) {
			return found.booleanValue();
514
		}
S
Sam Brannen 已提交
515
		found = Boolean.FALSE;
516 517 518
		for (Method ifcMethod : iface.getMethods()) {
			try {
				if (ifcMethod.getAnnotations().length > 0) {
519
					found = Boolean.TRUE;
520
					break;
521
				}
522 523
			}
			catch (Exception ex) {
524
				handleIntrospectionFailure(ifcMethod, ex);
525 526
			}
		}
527
		annotatedInterfaceCache.put(iface, found);
528
		return found.booleanValue();
529 530
	}

A
Arjen Poutsma 已提交
531
	/**
532 533
	 * Find a single {@link Annotation} of {@code annotationType} on the
	 * supplied {@link Class}, traversing its interfaces, annotations, and
534 535
	 * superclasses if the annotation is not <em>directly present</em> on
	 * the given class itself.
S
Sam Brannen 已提交
536
	 * <p>This method explicitly handles class-level annotations which are not
537 538
	 * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
	 * as meta-annotations and annotations on interfaces</em>.
S
Sam Brannen 已提交
539 540
	 * <p>The algorithm operates as follows:
	 * <ol>
541 542
	 * <li>Search for the annotation on the given class and return it if found.
	 * <li>Recursively search through all annotations that the given class declares.
543
	 * <li>Recursively search through all interfaces that the given class declares.
544
	 * <li>Recursively search through the superclass hierarchy of the given class.
S
Sam Brannen 已提交
545
	 * </ol>
546 547 548
	 * <p>Note: in this context, the term <em>recursively</em> means that the search
	 * process continues by returning to step #1 with the current interface,
	 * annotation, or superclass as the class to look for annotations on.
A
Arjen Poutsma 已提交
549
	 * @param clazz the class to look for annotations on
550
	 * @param annotationType the type of annotation to look for
551
	 * @return the first matching annotation, or {@code null} if not found
A
Arjen Poutsma 已提交
552
	 */
553
	@SuppressWarnings("unchecked")
A
Arjen Poutsma 已提交
554
	public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
555 556 557 558 559 560 561 562
		AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationType);
		A result = (A) findAnnotationCache.get(cacheKey);
		if (result == null) {
			result = findAnnotation(clazz, annotationType, new HashSet<Annotation>());
			if (result != null) {
				findAnnotationCache.put(cacheKey, result);
			}
		}
563
		return synthesizeAnnotation(result, clazz);
564 565 566 567 568
	}

	/**
	 * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
	 * avoiding endless recursion by tracking which annotations have already
S
Sam Brannen 已提交
569
	 * been <em>visited</em>.
570 571
	 * @param clazz the class to look for annotations on
	 * @param annotationType the type of annotation to look for
S
Sam Brannen 已提交
572
	 * @param visited the set of annotations that have already been visited
573
	 * @return the first matching annotation, or {@code null} if not found
574
	 */
575
	@SuppressWarnings("unchecked")
J
Juergen Hoeller 已提交
576
	private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
A
Arjen Poutsma 已提交
577
		Assert.notNull(clazz, "Class must not be null");
578 579 580 581 582 583 584

		try {
			Annotation[] anns = clazz.getDeclaredAnnotations();
			for (Annotation ann : anns) {
				if (ann.annotationType().equals(annotationType)) {
					return (A) ann;
				}
585
			}
586 587 588 589 590 591
			for (Annotation ann : anns) {
				if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
					A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
					if (annotation != null) {
						return annotation;
					}
592
				}
593
			}
A
Arjen Poutsma 已提交
594
		}
595
		catch (Exception ex) {
596
			handleIntrospectionFailure(clazz, ex);
597 598 599
			return null;
		}

A
Arjen Poutsma 已提交
600
		for (Class<?> ifc : clazz.getInterfaces()) {
601
			A annotation = findAnnotation(ifc, annotationType, visited);
A
Arjen Poutsma 已提交
602 603 604 605
			if (annotation != null) {
				return annotation;
			}
		}
606

607
		Class<?> superclass = clazz.getSuperclass();
608
		if (superclass == null || Object.class == superclass) {
A
Arjen Poutsma 已提交
609 610
			return null;
		}
S
Sam Brannen 已提交
611
		return findAnnotation(superclass, annotationType, visited);
A
Arjen Poutsma 已提交
612 613 614
	}

	/**
615 616 617 618 619 620 621
	 * Find the first {@link Class} in the inheritance hierarchy of the
	 * specified {@code clazz} (including the specified {@code clazz} itself)
	 * on which an annotation of the specified {@code annotationType} is
	 * <em>directly present</em>.
	 * <p>If the supplied {@code clazz} is an interface, only the interface
	 * itself will be checked; the inheritance hierarchy for interfaces will
	 * not be traversed.
622
	 * <p>Meta-annotations will <em>not</em> be searched.
623 624 625 626 627 628 629 630
	 * <p>The standard {@link Class} API does not provide a mechanism for
	 * determining which class in an inheritance hierarchy actually declares
	 * an {@link Annotation}, so we need to handle this explicitly.
	 * @param annotationType the annotation type to look for
	 * @param clazz the class to check for the annotation on (may be {@code null})
	 * @return the first {@link Class} in the inheritance hierarchy that
	 * declares an annotation of the specified {@code annotationType}, or
	 * {@code null} if not found
A
Arjen Poutsma 已提交
631 632
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
633 634
	 * @see #findAnnotationDeclaringClassForTypes(List, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
A
Arjen Poutsma 已提交
635 636 637
	 */
	public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
638
		if (clazz == null || Object.class == clazz) {
A
Arjen Poutsma 已提交
639 640
			return null;
		}
641 642 643 644
		if (isAnnotationDeclaredLocally(annotationType, clazz)) {
			return clazz;
		}
		return findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());
645 646 647
	}

	/**
648 649 650 651 652 653 654
	 * Find the first {@link Class} in the inheritance hierarchy of the
	 * specified {@code clazz} (including the specified {@code clazz} itself)
	 * on which at least one of the specified {@code annotationTypes} is
	 * <em>directly present</em>.
	 * <p>If the supplied {@code clazz} is an interface, only the interface
	 * itself will be checked; the inheritance hierarchy for interfaces will
	 * not be traversed.
655
	 * <p>Meta-annotations will <em>not</em> be searched.
656 657 658 659 660 661 662 663
	 * <p>The standard {@link Class} API does not provide a mechanism for
	 * determining which class in an inheritance hierarchy actually declares
	 * one of several candidate {@linkplain Annotation annotations}, so we
	 * need to handle this explicitly.
	 * @param annotationTypes the annotation types to look for
	 * @param clazz the class to check for the annotations on, or {@code null}
	 * @return the first {@link Class} in the inheritance hierarchy that
	 * declares an annotation of at least one of the specified
664
	 * {@code annotationTypes}, or {@code null} if not found
665
	 * @since 3.2.2
666 667 668 669 670
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
	 * @see #findAnnotationDeclaringClass(Class, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
	 */
671
	public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes, Class<?> clazz) {
672
		Assert.notEmpty(annotationTypes, "The list of annotation types must not be empty");
673
		if (clazz == null || Object.class == clazz) {
674 675 676 677 678 679 680 681
			return null;
		}
		for (Class<? extends Annotation> annotationType : annotationTypes) {
			if (isAnnotationDeclaredLocally(annotationType, clazz)) {
				return clazz;
			}
		}
		return findAnnotationDeclaringClassForTypes(annotationTypes, clazz.getSuperclass());
A
Arjen Poutsma 已提交
682 683 684
	}

	/**
685 686 687 688
	 * Determine whether an annotation of the specified {@code annotationType}
	 * is declared locally (i.e., <em>directly present</em>) on the supplied
	 * {@code clazz}.
	 * <p>The supplied {@link Class} may represent any type.
689
	 * <p>Meta-annotations will <em>not</em> be searched.
690 691 692
	 * <p>Note: This method does <strong>not</strong> determine if the annotation
	 * is {@linkplain java.lang.annotation.Inherited inherited}. For greater
	 * clarity regarding inherited annotations, consider using
S
Sam Brannen 已提交
693
	 * {@link #isAnnotationInherited(Class, Class)} instead.
694 695
	 * @param annotationType the annotation type to look for
	 * @param clazz the class to check for the annotation on
696
	 * @return {@code true} if an annotation of the specified {@code annotationType}
697
	 * is <em>directly present</em>
698 699
	 * @see java.lang.Class#getDeclaredAnnotations()
	 * @see java.lang.Class#getDeclaredAnnotation(Class)
A
Arjen Poutsma 已提交
700 701 702 703 704
	 * @see #isAnnotationInherited(Class, Class)
	 */
	public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
		Assert.notNull(clazz, "Class must not be null");
705
		try {
706 707
			for (Annotation ann : clazz.getDeclaredAnnotations()) {
				if (ann.annotationType().equals(annotationType)) {
708
					return true;
709
				}
A
Arjen Poutsma 已提交
710 711
			}
		}
712
		catch (Exception ex) {
713
			handleIntrospectionFailure(clazz, ex);
714
		}
715
		return false;
A
Arjen Poutsma 已提交
716 717 718
	}

	/**
719 720 721 722
	 * Determine whether an annotation of the specified {@code annotationType}
	 * is <em>present</em> on the supplied {@code clazz} and is
	 * {@linkplain java.lang.annotation.Inherited inherited} (i.e., not
	 * <em>directly present</em>).
723
	 * <p>Meta-annotations will <em>not</em> be searched.
724 725 726 727 728 729 730 731 732 733
	 * <p>If the supplied {@code clazz} is an interface, only the interface
	 * itself will be checked. In accordance with standard meta-annotation
	 * semantics in Java, the inheritance hierarchy for interfaces will not
	 * be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc}
	 * for the {@code @Inherited} meta-annotation for further details regarding
	 * annotation inheritance.
	 * @param annotationType the annotation type to look for
	 * @param clazz the class to check for the annotation on
	 * @return {@code true} if an annotation of the specified {@code annotationType}
	 * is <em>present</em> and <em>inherited</em>
A
Arjen Poutsma 已提交
734 735 736 737 738 739 740 741 742
	 * @see Class#isAnnotationPresent(Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
	 */
	public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
		Assert.notNull(clazz, "Class must not be null");
		return (clazz.isAnnotationPresent(annotationType) && !isAnnotationDeclaredLocally(annotationType, clazz));
	}

743
	/**
J
Juergen Hoeller 已提交
744
	 * Determine if the supplied {@link Annotation} is defined in the core JDK
745
	 * {@code java.lang.annotation} package.
J
Juergen Hoeller 已提交
746
	 * @param annotation the annotation to check (never {@code null})
747 748 749 750
	 * @return {@code true} if the annotation is in the {@code java.lang.annotation} package
	 */
	public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
		Assert.notNull(annotation, "Annotation must not be null");
751 752 753 754 755 756 757 758 759 760 761 762 763
		return isInJavaLangAnnotationPackage(annotation.annotationType().getName());
	}

	/**
	 * Determine if the {@link Annotation} with the supplied name is defined
	 * in the core JDK {@code java.lang.annotation} package.
	 * @param annotationType the name of the annotation type to check (never {@code null} or empty)
	 * @return {@code true} if the annotation is in the {@code java.lang.annotation} package
	 * @since 4.2
	 */
	public static boolean isInJavaLangAnnotationPackage(String annotationType) {
		Assert.hasText(annotationType, "annotationType must not be null or empty");
		return annotationType.startsWith("java.lang.annotation");
764 765
	}

A
Arjen Poutsma 已提交
766
	/**
J
Juergen Hoeller 已提交
767
	 * Retrieve the given annotation's attributes as a {@link Map}, preserving all
768 769 770 771
	 * attribute types.
	 * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)}
	 * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters
	 * set to {@code false}.
J
Juergen Hoeller 已提交
772 773
	 * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
	 * However, the {@code Map} signature has been preserved for binary compatibility.
A
Arjen Poutsma 已提交
774
	 * @param annotation the annotation to retrieve the attributes for
J
Juergen Hoeller 已提交
775
	 * @return the Map of annotation attributes, with attribute names as keys and
776
	 * corresponding attribute values as values; never {@code null}
777
	 * @see #getAnnotationAttributes(AnnotatedElement, Annotation)
778
	 * @see #getAnnotationAttributes(Annotation, boolean, boolean)
779
	 * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
A
Arjen Poutsma 已提交
780 781
	 */
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
782
		return getAnnotationAttributes(null, annotation);
783 784 785
	}

	/**
786 787 788
	 * Retrieve the given annotation's attributes as a {@link Map}.
	 * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)}
	 * with the {@code nestedAnnotationsAsMap} parameter set to {@code false}.
J
Juergen Hoeller 已提交
789 790
	 * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
	 * However, the {@code Map} signature has been preserved for binary compatibility.
791
	 * @param annotation the annotation to retrieve the attributes for
792
	 * @param classValuesAsString whether to convert Class references into Strings (for
S
Sam Brannen 已提交
793
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
J
Juergen Hoeller 已提交
794
	 * or to preserve them as Class references
J
Juergen Hoeller 已提交
795
	 * @return the Map of annotation attributes, with attribute names as keys and
796 797
	 * corresponding attribute values as values; never {@code null}
	 * @see #getAnnotationAttributes(Annotation, boolean, boolean)
798
	 */
799
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {
800 801 802 803
		return getAnnotationAttributes(annotation, classValuesAsString, false);
	}

	/**
804
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
J
Juergen Hoeller 已提交
805 806
	 * <p>This method provides fully recursive annotation reading capabilities on par with
	 * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
807
	 * @param annotation the annotation to retrieve the attributes for
808
	 * @param classValuesAsString whether to convert Class references into Strings (for
S
Sam Brannen 已提交
809
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
J
Juergen Hoeller 已提交
810
	 * or to preserve them as Class references
811
	 * @param nestedAnnotationsAsMap whether to convert nested annotations into
812
	 * {@link AnnotationAttributes} maps (for compatibility with
S
Sam Brannen 已提交
813
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
814
	 * {@code Annotation} instances
815
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
816
	 * and corresponding attribute values as values; never {@code null}
817 818
	 * @since 3.1.1
	 */
819 820
	public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString,
			boolean nestedAnnotationsAsMap) {
821 822
		return getAnnotationAttributes(null, annotation, classValuesAsString, nestedAnnotationsAsMap);
	}
823

824 825 826 827 828
	/**
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
	 * <p>Equivalent to calling {@link #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)}
	 * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters
	 * set to {@code false}.
829 830
	 * @param annotatedElement the element that is annotated with the supplied annotation;
	 * may be {@code null} if unknown
831
	 * @param annotation the annotation to retrieve the attributes for
832 833
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
	 * and corresponding attribute values as values; never {@code null}
834
	 * @since 4.2
835
	 * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
836 837 838 839 840 841 842 843 844
	 */
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement, Annotation annotation) {
		return getAnnotationAttributes(annotatedElement, annotation, false, false);
	}

	/**
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
	 * <p>This method provides fully recursive annotation reading capabilities on par with
	 * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
845 846
	 * @param annotatedElement the element that is annotated with the supplied annotation;
	 * may be {@code null} if unknown
847 848 849 850
	 * @param annotation the annotation to retrieve the attributes for
	 * @param classValuesAsString whether to convert Class references into Strings (for
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
	 * or to preserve them as Class references
851
	 * @param nestedAnnotationsAsMap whether to convert nested annotations into
852 853
	 * {@link AnnotationAttributes} maps (for compatibility with
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
854
	 * {@code Annotation} instances
855 856 857 858 859 860 861
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
	 * and corresponding attribute values as values; never {@code null}
	 * @since 4.2
	 */
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
			Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {

862
		return getAnnotationAttributes(annotatedElement, annotation, classValuesAsString, nestedAnnotationsAsMap, false);
863 864 865 866 867 868 869 870
	}

	/**
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
	 *
	 * <p>This method provides fully recursive annotation reading capabilities on par with
	 * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
	 *
871 872 873 874 875
	 * <p><strong>NOTE</strong>: This variant of {@code getAnnotationAttributes()} is
	 * only intended for use within the framework. Specifically, the {@code mergeMode} flag
	 * can be set to {@code true} in order to support processing of attribute aliases while
	 * merging attributes within an annotation hierarchy. When running in <em>merge mode</em>,
	 * the following special rules apply:
876
	 * <ol>
877 878 879 880
	 * <li>The supplied annotation will <em>not</em> be
	 * {@linkplain #synthesizeAnnotation synthesized} before retrieving its attributes;
	 * however, nested annotations and arrays of nested annotations <em>will</em> be
	 * synthesized.</li>
881
	 * <li>Default values will be replaced with {@link #DEFAULT_VALUE_PLACEHOLDER}.</li>
882 883 884 885 886 887 888 889
	 * <li>The resulting, merged annotation attributes should eventually be
	 * {@linkplain #postProcessAnnotationAttributes post-processed} in order to
	 * ensure that placeholders have been replaced by actual default values and
	 * in order to enforce {@code @AliasFor} semantics.</li>
	 * </ol>
	 *
	 * @param annotatedElement the element that is annotated with the supplied annotation;
	 * may be {@code null} if unknown
890 891 892 893
	 * @param annotation the annotation to retrieve the attributes for
	 * @param classValuesAsString whether to convert Class references into Strings (for
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
	 * or to preserve them as Class references
894
	 * @param nestedAnnotationsAsMap whether to convert nested annotations into
895 896
	 * {@link AnnotationAttributes} maps (for compatibility with
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
897
	 * {@code Annotation} instances
898 899
	 * @param mergeMode whether the annotation attributes should be created
	 * using <em>merge mode</em>
900 901 902
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
	 * and corresponding attribute values as values; never {@code null}
	 * @since 4.2
903
	 * @see #postProcessAnnotationAttributes
904
	 */
905
	static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement, Annotation annotation,
906
			boolean classValuesAsString, boolean nestedAnnotationsAsMap, boolean mergeMode) {
907

908
		if (!mergeMode) {
909
			annotation = synthesizeAnnotation(annotation, annotatedElement);
910 911 912 913 914 915 916 917
		}

		Class<? extends Annotation> annotationType = annotation.annotationType();
		AnnotationAttributes attrs = new AnnotationAttributes(annotationType);
		for (Method method : getAttributeMethods(annotationType)) {
			try {
				Object value = method.invoke(annotation);
				Object defaultValue = method.getDefaultValue();
918
				if (mergeMode && (defaultValue != null)) {
919 920 921
					if (ObjectUtils.nullSafeEquals(value, defaultValue)) {
						value = DEFAULT_VALUE_PLACEHOLDER;
					}
A
Arjen Poutsma 已提交
922
				}
923 924 925 926 927 928 929
				attrs.put(method.getName(),
					adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap));
			}
			catch (Exception ex) {
				if (ex instanceof InvocationTargetException) {
					Throwable targetException = ((InvocationTargetException) ex).getTargetException();
					rethrowAnnotationConfigurationException(targetException);
A
Arjen Poutsma 已提交
930
				}
931
				throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex);
A
Arjen Poutsma 已提交
932 933 934 935 936
			}
		}
		return attrs;
	}

937 938
	/**
	 * Adapt the given value according to the given class and nested annotation settings.
939
	 * <p>Nested annotations will be
940
	 * {@linkplain #synthesizeAnnotation(Annotation, AnnotatedElement) synthesized}.
941 942
	 * @param annotatedElement the element that is annotated, used for contextual
	 * logging; may be {@code null} if unknown
943
	 * @param value the annotation attribute value
944
	 * @param classValuesAsString whether to convert Class references into Strings (for
S
Sam Brannen 已提交
945
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
946
	 * or to preserve them as Class references
947
	 * @param nestedAnnotationsAsMap whether to convert nested annotations into
948
	 * {@link AnnotationAttributes} maps (for compatibility with
S
Sam Brannen 已提交
949
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
950
	 * {@code Annotation} instances
951 952
	 * @return the adapted value, or the original value if no adaptation is needed
	 */
953 954 955
	static Object adaptValue(AnnotatedElement annotatedElement, Object value, boolean classValuesAsString,
			boolean nestedAnnotationsAsMap) {

956 957
		if (classValuesAsString) {
			if (value instanceof Class) {
958
				return ((Class<?>) value).getName();
959 960
			}
			else if (value instanceof Class[]) {
961
				Class<?>[] clazzArray = (Class<?>[]) value;
962
				String[] classNames = new String[clazzArray.length];
963
				for (int i = 0; i < clazzArray.length; i++) {
964
					classNames[i] = clazzArray[i].getName();
965
				}
966
				return classNames;
967 968
			}
		}
969 970 971 972 973 974 975 976 977

		if (value instanceof Annotation) {
			Annotation annotation = (Annotation) value;

			if (nestedAnnotationsAsMap) {
				return getAnnotationAttributes(annotatedElement, annotation, classValuesAsString,
					nestedAnnotationsAsMap);
			}
			else {
978
				return synthesizeAnnotation(annotation, annotatedElement);
979 980
			}
		}
981 982 983 984 985 986 987 988 989 990 991 992 993

		if (value instanceof Annotation[]) {
			Annotation[] annotations = (Annotation[]) value;

			if (nestedAnnotationsAsMap) {
				AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[annotations.length];
				for (int i = 0; i < annotations.length; i++) {
					mappedAnnotations[i] = getAnnotationAttributes(annotatedElement, annotations[i],
						classValuesAsString, nestedAnnotationsAsMap);
				}
				return mappedAnnotations;
			}
			else {
994
				return synthesizeAnnotationArray(annotations, annotatedElement);
995
			}
996
		}
997 998 999

		// Fallback
		return value;
1000 1001
	}

A
Arjen Poutsma 已提交
1002
	/**
1003
	 * Retrieve the <em>value</em> of the {@code value} attribute of a
J
Juergen Hoeller 已提交
1004
	 * single-element Annotation, given an annotation instance.
A
Arjen Poutsma 已提交
1005
	 * @param annotation the annotation instance from which to retrieve the value
1006
	 * @return the attribute value, or {@code null} if not found
A
Arjen Poutsma 已提交
1007 1008 1009 1010 1011 1012 1013
	 * @see #getValue(Annotation, String)
	 */
	public static Object getValue(Annotation annotation) {
		return getValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
1014
	 * Retrieve the <em>value</em> of a named attribute, given an annotation instance.
A
Arjen Poutsma 已提交
1015 1016
	 * @param annotation the annotation instance from which to retrieve the value
	 * @param attributeName the name of the attribute value to retrieve
1017
	 * @return the attribute value, or {@code null} if not found
J
Juergen Hoeller 已提交
1018
	 * @see #getValue(Annotation)
A
Arjen Poutsma 已提交
1019 1020
	 */
	public static Object getValue(Annotation annotation, String attributeName) {
1021
		if (annotation == null || !StringUtils.hasText(attributeName)) {
1022 1023
			return null;
		}
A
Arjen Poutsma 已提交
1024
		try {
J
Juergen Hoeller 已提交
1025
			Method method = annotation.annotationType().getDeclaredMethod(attributeName);
1026
			ReflectionUtils.makeAccessible(method);
A
Arjen Poutsma 已提交
1027 1028 1029 1030 1031 1032 1033 1034
			return method.invoke(annotation);
		}
		catch (Exception ex) {
			return null;
		}
	}

	/**
1035
	 * Retrieve the <em>default value</em> of the {@code value} attribute
J
Juergen Hoeller 已提交
1036 1037
	 * of a single-element Annotation, given an annotation instance.
	 * @param annotation the annotation instance from which to retrieve the default value
1038
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
1039 1040 1041 1042 1043 1044 1045
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Annotation annotation) {
		return getDefaultValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
1046
	 * Retrieve the <em>default value</em> of a named attribute, given an annotation instance.
J
Juergen Hoeller 已提交
1047
	 * @param annotation the annotation instance from which to retrieve the default value
A
Arjen Poutsma 已提交
1048
	 * @param attributeName the name of the attribute value to retrieve
1049
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
1050 1051 1052
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Annotation annotation, String attributeName) {
1053 1054 1055
		if (annotation == null) {
			return null;
		}
A
Arjen Poutsma 已提交
1056 1057 1058 1059
		return getDefaultValue(annotation.annotationType(), attributeName);
	}

	/**
1060
	 * Retrieve the <em>default value</em> of the {@code value} attribute
J
Juergen Hoeller 已提交
1061 1062
	 * of a single-element Annotation, given the {@link Class annotation type}.
	 * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
1063
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
1064 1065 1066 1067 1068 1069 1070
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType) {
		return getDefaultValue(annotationType, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
1071 1072
	 * Retrieve the <em>default value</em> of a named attribute, given the
	 * {@link Class annotation type}.
J
Juergen Hoeller 已提交
1073
	 * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
A
Arjen Poutsma 已提交
1074
	 * @param attributeName the name of the attribute value to retrieve.
1075
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
1076 1077 1078
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
1079
		if (annotationType == null || !StringUtils.hasText(attributeName)) {
1080 1081
			return null;
		}
A
Arjen Poutsma 已提交
1082
		try {
J
Juergen Hoeller 已提交
1083
			return annotationType.getDeclaredMethod(attributeName).getDefaultValue();
A
Arjen Poutsma 已提交
1084 1085 1086 1087 1088 1089
		}
		catch (Exception ex) {
			return null;
		}
	}

1090
	/**
1091 1092 1093 1094
	 * <em>Synthesize</em> an annotation from the supplied {@code annotation}
	 * by wrapping it in a dynamic proxy that transparently enforces
	 * <em>attribute alias</em> semantics for annotation attributes that are
	 * annotated with {@link AliasFor @AliasFor}.
1095 1096
	 *
	 * @param annotation the annotation to synthesize
1097 1098 1099 1100 1101
	 * @return the synthesized annotation, if the supplied annotation is
	 * <em>synthesizable</em>; {@code null} if the supplied annotation is
	 * {@code null}; otherwise, the supplied annotation unmodified
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
1102
	 * @since 4.2
1103
	 * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
1104
	 */
1105 1106
	static <A extends Annotation> A synthesizeAnnotation(A annotation) {
		return synthesizeAnnotation(annotation, null);
1107 1108 1109
	}

	/**
1110 1111 1112 1113
	 * <em>Synthesize</em> an annotation from the supplied {@code annotation}
	 * by wrapping it in a dynamic proxy that transparently enforces
	 * <em>attribute alias</em> semantics for annotation attributes that are
	 * annotated with {@link AliasFor @AliasFor}.
1114 1115
	 *
	 * @param annotation the annotation to synthesize
1116 1117
	 * @param annotatedElement the element that is annotated with the supplied
	 * annotation; may be {@code null} if unknown
1118
	 * @return the synthesized annotation if the supplied annotation is
1119
	 * <em>synthesizable</em>; {@code null} if the supplied annotation is
1120
	 * {@code null}; otherwise the supplied annotation unmodified
1121 1122
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
1123
	 * @since 4.2
1124
	 * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
1125 1126
	 */
	@SuppressWarnings("unchecked")
1127
	public static <A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement) {
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
		if (annotation == null) {
			return null;
		}
		if (annotation instanceof SynthesizedAnnotation) {
			return annotation;
		}

		Class<? extends Annotation> annotationType = annotation.annotationType();
		if (!isSynthesizable(annotationType)) {
			return annotation;
		}

1140 1141 1142
		AnnotationAttributeExtractor attributeExtractor = new DefaultAnnotationAttributeExtractor(annotation,
			annotatedElement);
		InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
1143 1144 1145 1146 1147 1148
		A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class<?>[] {
			(Class<A>) annotationType, SynthesizedAnnotation.class }, handler);

		return synthesizedAnnotation;
	}

1149
	/**
1150 1151 1152 1153 1154
	 * <em>Synthesize</em> an annotation from the supplied map of annotation
	 * attributes by wrapping the map in a dynamic proxy that implements an
	 * annotation of the specified {@code annotationType} and transparently
	 * enforces <em>attribute alias</em> semantics for annotation attributes
	 * that are annotated with {@link AliasFor @AliasFor}.
1155 1156 1157
	 * <p>The supplied map must contain a key-value pair for every attribute
	 * defined in the supplied {@code annotationType} that is not aliased or
	 * does not have a default value.
1158
	 * <p>Note that {@link AnnotationAttributes} is a specialized type of
1159
	 * {@link Map} that is an ideal candidate for this method's
1160 1161 1162 1163 1164 1165 1166 1167
	 * {@code attributes} argument.
	 *
	 * @param attributes the map of annotation attributes to synthesize
	 * @param annotationType the type of annotation to synthesize; never {@code null}
	 * @param annotatedElement the element that is annotated with the annotation
	 * corresponding to the supplied attributes; may be {@code null} if unknown
	 * @return the synthesized annotation, or {@code null} if the supplied attributes
	 * map is {@code null}
1168 1169 1170 1171
	 * @throws IllegalArgumentException if a required attribute is missing or if an
	 * attribute is not of the correct type
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
	 * @since 4.2
	 * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
	 */
	@SuppressWarnings("unchecked")
	public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes,
			Class<A> annotationType, AnnotatedElement annotatedElement) {
		Assert.notNull(annotationType, "annotationType must not be null");

		if (attributes == null) {
			return null;
		}

		AnnotationAttributeExtractor attributeExtractor = new MapAnnotationAttributeExtractor(attributes,
			annotationType, annotatedElement);
		InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
		A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class<?>[] {
			annotationType, SynthesizedAnnotation.class }, handler);

		return synthesizedAnnotation;
	}
1192

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
	/**
	 * <em>Synthesize</em> the supplied array of {@code annotations} by
	 * creating a new array of the same size and type and populating it
	 * with {@linkplain #synthesizeAnnotation(Annotation) synthesized}
	 * versions of the annotations from the input array.
	 *
	 * @param annotations the array of annotations to synthesize
	 * @param annotatedElement the element that is annotated with the supplied
	 * array of annotations; may be {@code null} if unknown
	 * @return a new array of synthesized annotations, or {@code null} if
	 * the supplied array is {@code null}
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
	 * @since 4.2
	 * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
	 * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
	 */
	public static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, AnnotatedElement annotatedElement) {
		if (annotations == null) {
			return null;
		}

		Annotation[] synthesized = (Annotation[]) Array.newInstance(annotations.getClass().getComponentType(), annotations.length);
		for (int i = 0; i < annotations.length; i++) {
			synthesized[i] = synthesizeAnnotation(annotations[i], annotatedElement);
		}
		return synthesized;
	}

1222
	/**
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
	 * Get a map of all attribute alias pairs, declared via {@code @AliasFor}
	 * in the supplied annotation type.
	 *
	 * <p>The map is keyed by attribute name with each value representing
	 * the name of the aliased attribute. For each entry {@code [x, y]} in
	 * the map there will be a corresponding {@code [y, x]} entry in the map.
	 *
	 * <p>An empty return value implies that the annotation does not declare
	 * any attribute aliases.
	 *
	 * @param annotationType the annotation type to find attribute aliases in
	 * @return a map containing attribute alias pairs; never {@code null}
1235 1236
	 * @since 4.2
	 */
1237
	static Map<String, String> getAttributeAliasMap(Class<? extends Annotation> annotationType) {
1238
		if (annotationType == null) {
1239 1240 1241
			return Collections.emptyMap();
		}

S
Sam Brannen 已提交
1242 1243 1244
		Map<String, String> map = attributeAliasesCache.get(annotationType);
		if (map != null) {
			return map;
1245 1246
		}

S
Sam Brannen 已提交
1247
		map = new HashMap<String, String>();
1248 1249 1250 1251 1252 1253 1254
		for (Method attribute : getAttributeMethods(annotationType)) {
			String attributeName = attribute.getName();
			String aliasedAttributeName = getAliasedAttributeName(attribute);
			if (aliasedAttributeName != null) {
				map.put(attributeName, aliasedAttributeName);
			}
		}
1255

S
Sam Brannen 已提交
1256
		attributeAliasesCache.put(annotationType, map);
1257

1258 1259 1260 1261
		return map;
	}

	/**
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
	 * Determine if annotations of the supplied {@code annotationType} are
	 * <em>synthesizable</em> (i.e., in need of being wrapped in a dynamic
	 * proxy that provides functionality above that of a standard JDK
	 * annotation).
	 *
	 * <p>Specifically, an annotation is <em>synthesizable</em> if it declares
	 * any attributes that are configured as <em>aliased pairs</em> via
	 * {@link AliasFor @AliasFor} or if any nested annotations used by the
	 * annotation declare such <em>aliased pairs</em>.
	 *
1272
	 * @since 4.2
1273 1274
	 * @see SynthesizedAnnotation
	 * @see SynthesizedAnnotationInvocationHandler
1275 1276 1277 1278
	 */
	@SuppressWarnings("unchecked")
	private static boolean isSynthesizable(Class<? extends Annotation> annotationType) {

S
Sam Brannen 已提交
1279 1280 1281
		Boolean synthesizable = synthesizableCache.get(annotationType);
		if (synthesizable != null) {
			return synthesizable.booleanValue();
1282 1283
		}

S
Sam Brannen 已提交
1284
		synthesizable = Boolean.FALSE;
1285

1286 1287
		for (Method attribute : getAttributeMethods(annotationType)) {
			if (getAliasedAttributeName(attribute) != null) {
1288 1289
				synthesizable = Boolean.TRUE;
				break;
1290 1291 1292 1293 1294 1295 1296
			}

			Class<?> returnType = attribute.getReturnType();

			if (Annotation[].class.isAssignableFrom(returnType)) {
				Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType.getComponentType();
				if (isSynthesizable(nestedAnnotationType)) {
1297 1298
					synthesizable = Boolean.TRUE;
					break;
1299 1300 1301 1302 1303
				}
			}
			else if (Annotation.class.isAssignableFrom(returnType)) {
				Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType;
				if (isSynthesizable(nestedAnnotationType)) {
1304 1305
					synthesizable = Boolean.TRUE;
					break;
1306 1307 1308 1309
				}
			}
		}

1310 1311 1312
		synthesizableCache.put(annotationType, synthesizable);

		return synthesizable.booleanValue();
1313
	}
1314

1315
	/**
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
	 * Get the name of the aliased attribute configured via
	 * {@link AliasFor @AliasFor} on the supplied annotation {@code attribute}.
	 *
	 * <p>This method does not resolve aliases in other annotations. In
	 * other words, if {@code @AliasFor} is present on the supplied
	 * {@code attribute} but {@linkplain AliasFor#annotation references an
	 * annotation} other than {@link Annotation}, this method will return
	 * {@code null} immediately.
	 *
	 * @param attribute the attribute to find an alias for
	 * @return the name of the aliased attribute, or {@code null} if not found
	 * @throws IllegalArgumentException if the supplied attribute method is
	 * not from an annotation, or if the supplied target type is {@link Annotation}
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
	 * @since 4.2
1332
	 * @see #getAliasedAttributeName(Method, Class)
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
	 */
	static String getAliasedAttributeName(Method attribute) {
		return getAliasedAttributeName(attribute, null);
	}

	/**
	 * Get the name of the aliased attribute configured via
	 * {@link AliasFor @AliasFor} on the supplied annotation {@code attribute}.
	 *
	 * @param attribute the attribute to find an alias for
	 * @param targetAnnotationType the type of annotation in which the
	 * aliased attribute is allowed to be declared; {@code null} implies
	 * <em>within the same annotation</em>
	 * @return the name of the aliased attribute, or {@code null} if not found
	 * @throws IllegalArgumentException if the supplied attribute method is
	 * not from an annotation, or if the supplied target type is {@link Annotation}
	 * @throws AnnotationConfigurationException if invalid configuration of
	 * {@code @AliasFor} is detected
	 * @since 4.2
	 */
	@SuppressWarnings("unchecked")
	static String getAliasedAttributeName(Method attribute, Class<? extends Annotation> targetAnnotationType) {
		Class<?> declaringClass = attribute.getDeclaringClass();
		Assert.isTrue(declaringClass.isAnnotation(), "attribute method must be from an annotation");
		Assert.isTrue(!Annotation.class.equals(targetAnnotationType),
			"targetAnnotationType must not be java.lang.annotation.Annotation");

		AliasFor aliasFor = attribute.getAnnotation(AliasFor.class);

		// Nothing to check
		if (aliasFor == null) {
			return null;
		}

		Class<? extends Annotation> sourceAnnotationType = (Class<? extends Annotation>) declaringClass;
		Class<? extends Annotation> aliasedAnnotationType = aliasFor.annotation();

		boolean searchWithinSameAnnotation = (targetAnnotationType == null);
		boolean sameTargetDeclared = (sourceAnnotationType.equals(aliasedAnnotationType) || Annotation.class.equals(aliasedAnnotationType));

		// Wrong search scope?
		if (searchWithinSameAnnotation && !sameTargetDeclared) {
			return null;
		}

		String attributeName = attribute.getName();
		String aliasedAttributeName = aliasFor.attribute();

		if (!StringUtils.hasText(aliasedAttributeName)) {
			String msg = String.format(
				"@AliasFor declaration on attribute [%s] in annotation [%s] is missing required 'attribute' value.",
				attributeName, sourceAnnotationType.getName());
			throw new AnnotationConfigurationException(msg);
		}

		if (sameTargetDeclared) {
			aliasedAnnotationType = sourceAnnotationType;
		}

		Method aliasedAttribute = null;
		try {
			aliasedAttribute = aliasedAnnotationType.getDeclaredMethod(aliasedAttributeName);
		}
		catch (NoSuchMethodException e) {
			String msg = String.format(
				"Attribute [%s] in annotation [%s] is declared as an @AliasFor nonexistent attribute [%s] in annotation [%s].",
				attributeName, sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName());
			throw new AnnotationConfigurationException(msg, e);
		}

		if (sameTargetDeclared) {
			AliasFor mirrorAliasFor = aliasedAttribute.getAnnotation(AliasFor.class);
			if (mirrorAliasFor == null) {
				String msg = String.format("Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s].",
					aliasedAttributeName, sourceAnnotationType.getName(), attributeName);
				throw new AnnotationConfigurationException(msg);
			}

			String mirrorAliasedAttributeName = mirrorAliasFor.attribute();
			if (!attributeName.equals(mirrorAliasedAttributeName)) {
				String msg = String.format(
					"Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].",
					aliasedAttributeName, sourceAnnotationType.getName(), attributeName, mirrorAliasedAttributeName);
				throw new AnnotationConfigurationException(msg);
			}
		}

		Class<?> returnType = attribute.getReturnType();
		Class<?> aliasedReturnType = aliasedAttribute.getReturnType();
		if (!returnType.equals(aliasedReturnType)) {
			String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] "
					+ "and attribute [%s] in annotation [%s] must declare the same return type.", attributeName,
				sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName());
			throw new AnnotationConfigurationException(msg);
		}

		if (sameTargetDeclared) {
			Object defaultValue = attribute.getDefaultValue();
			Object aliasedDefaultValue = aliasedAttribute.getDefaultValue();

			if ((defaultValue == null) || (aliasedDefaultValue == null)) {
				String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] "
						+ "and attribute [%s] in annotation [%s] must declare default values.", attributeName,
					sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName());
				throw new AnnotationConfigurationException(msg);
			}

			if (!ObjectUtils.nullSafeEquals(defaultValue, aliasedDefaultValue)) {
				String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] "
						+ "and attribute [%s] in annotation [%s] must declare the same default value.", attributeName,
					sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName());
				throw new AnnotationConfigurationException(msg);
			}
		}

		return aliasedAttributeName;
	}

	/**
1452 1453
	 * Get all methods declared in the supplied {@code annotationType} that
	 * match Java's requirements for annotation <em>attributes</em>.
1454
	 *
1455 1456 1457
	 * <p>All methods in the returned list will be
	 * {@linkplain ReflectionUtils#makeAccessible(Method) made accessible}.
	 *
S
Sam Brannen 已提交
1458 1459
	 * @param annotationType the type in which to search for attribute methods;
	 * never {@code null}
1460 1461
	 * @return all annotation attribute methods in the specified annotation
	 * type; never {@code null}, though potentially <em>empty</em>
1462 1463 1464
	 * @since 4.2
	 */
	static List<Method> getAttributeMethods(Class<? extends Annotation> annotationType) {
1465 1466 1467 1468 1469 1470 1471

		List<Method> methods = attributeMethodsCache.get(annotationType);
		if (methods != null) {
			return methods;
		}

		methods = new ArrayList<Method>();
1472
		for (Method method : annotationType.getDeclaredMethods()) {
1473
			if (isAttributeMethod(method)) {
1474
				ReflectionUtils.makeAccessible(method);
1475 1476 1477
				methods.add(method);
			}
		}
1478 1479 1480

		attributeMethodsCache.put(annotationType, methods);

1481 1482 1483
		return methods;
	}

1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
	/**
	 * Determine if the supplied {@code method} is an annotation attribute method.
	 * @param method the method to check
	 * @return {@code true} if the method is an attribute method
	 */
	static boolean isAttributeMethod(Method method) {
		return ((method != null) && (method.getParameterTypes().length == 0) && (method.getReturnType() != void.class));
	}

	/**
	 * Determine if the supplied method is an "annotationType" method.
	 * @return {@code true} if the method is an "annotationType" method
	 * @see Annotation#annotationType()
	 */
	static boolean isAnnotationTypeMethod(Method method) {
		return ((method != null) && method.getName().equals("annotationType") && (method.getParameterTypes().length == 0));
	}

1502
	/**
1503
	 * Post-process the supplied {@link AnnotationAttributes}.
1504
	 *
1505 1506 1507 1508 1509 1510 1511 1512
	 * <p>Specifically, this method enforces <em>attribute alias</em> semantics
	 * for annotation attributes that are annotated with {@link AliasFor @AliasFor}
	 * and replaces {@linkplain #DEFAULT_VALUE_PLACEHOLDER placeholders} with their
	 * original default values.
	 *
	 * @param element the element that is annotated with an annotation or
	 * annotation hierarchy from which the supplied attributes were created;
	 * may be {@code null} if unknown
1513
	 * @param attributes the annotation attributes to post-process
1514 1515 1516 1517 1518 1519 1520
	 * @param classValuesAsString whether to convert Class references into Strings (for
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
	 * or to preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to convert nested annotations into
	 * {@link AnnotationAttributes} maps (for compatibility with
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
	 * {@code Annotation} instances
1521
	 * @since 4.2
1522 1523 1524
	 * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean, boolean)
	 * @see #DEFAULT_VALUE_PLACEHOLDER
	 * @see #getDefaultValue(Class, String)
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
	 */
	static void postProcessAnnotationAttributes(AnnotatedElement element, AnnotationAttributes attributes,
			boolean classValuesAsString, boolean nestedAnnotationsAsMap) {

		// Abort?
		if (attributes == null) {
			return;
		}

		Class<? extends Annotation> annotationType = attributes.annotationType();

		// Validate @AliasFor configuration
1537 1538 1539 1540 1541 1542 1543 1544 1545
		Map<String, String> aliasMap = getAttributeAliasMap(annotationType);
		Set<String> validated = new HashSet<String>();
		for (String attributeName : aliasMap.keySet()) {
			String aliasedAttributeName = aliasMap.get(attributeName);

			if (validated.add(attributeName) && validated.add(aliasedAttributeName)) {
				Object value = attributes.get(attributeName);
				Object aliasedValue = attributes.get(aliasedAttributeName);

1546 1547
				if (!ObjectUtils.nullSafeEquals(value, aliasedValue) && (value != DEFAULT_VALUE_PLACEHOLDER)
						&& (aliasedValue != DEFAULT_VALUE_PLACEHOLDER)) {
1548 1549 1550 1551 1552 1553 1554 1555
					String elementAsString = (element == null ? "unknown element" : element.toString());
					String msg = String.format(
						"In AnnotationAttributes for annotation [%s] declared on [%s], attribute [%s] and its alias [%s] are "
								+ "declared with values of [%s] and [%s], but only one declaration is permitted.",
						annotationType.getName(), elementAsString, attributeName, aliasedAttributeName,
						ObjectUtils.nullSafeToString(value), ObjectUtils.nullSafeToString(aliasedValue));
					throw new AnnotationConfigurationException(msg);
				}
1556

1557
				// Replace default values with aliased values...
1558
				if (value == DEFAULT_VALUE_PLACEHOLDER) {
1559 1560 1561
					attributes.put(attributeName,
						adaptValue(element, aliasedValue, classValuesAsString, nestedAnnotationsAsMap));
				}
1562
				if (aliasedValue == DEFAULT_VALUE_PLACEHOLDER) {
1563 1564
					attributes.put(aliasedAttributeName,
						adaptValue(element, value, classValuesAsString, nestedAnnotationsAsMap));
1565 1566 1567 1568 1569 1570
				}
			}
		}

		for (String attributeName : attributes.keySet()) {
			Object value = attributes.get(attributeName);
1571
			if (value == DEFAULT_VALUE_PLACEHOLDER) {
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
				attributes.put(attributeName,
					adaptValue(element, getDefaultValue(annotationType, attributeName), classValuesAsString,
						nestedAnnotationsAsMap));
			}
		}
	}

	/**
	 * <p>If the supplied throwable is an {@link AnnotationConfigurationException},
	 * it will be cast to an {@code AnnotationConfigurationException} and thrown,
	 * allowing it to propagate to the caller.
	 * <p>Otherwise, this method does nothing.
1584
	 * @param t the throwable to inspect
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
	 * @since 4.2
	 */
	static void rethrowAnnotationConfigurationException(Throwable t) {
		if (t instanceof AnnotationConfigurationException) {
			throw (AnnotationConfigurationException) t;
		}
	}

	/**
	 * Handle the supplied annotation introspection exception.
	 * <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
1599 1600 1601 1602 1603
	 * {@code TypeNotPresentExceptions}) before moving on, assuming nested
	 * Class values were not resolvable within annotation attributes and
	 * thereby effectively pretending there were no annotations on the specified
	 * element.
	 *
1604 1605
	 * @param element the element that we tried to introspect annotations on
	 * @param ex the exception that we encountered
1606
	 * @see #rethrowAnnotationConfigurationException
1607
	 */
1608 1609 1610 1611
	static void handleIntrospectionFailure(AnnotatedElement element, Exception ex) {

		rethrowAnnotationConfigurationException(ex);

1612 1613 1614 1615 1616
		Log loggerToUse = logger;
		if (loggerToUse == null) {
			loggerToUse = LogFactory.getLog(AnnotationUtils.class);
			logger = loggerToUse;
		}
1617
		if ((element instanceof Class) && Annotation.class.isAssignableFrom((Class<?>) element)) {
1618
			// Meta-annotation lookup on an annotation type
1619 1620
			if (loggerToUse.isDebugEnabled()) {
				loggerToUse.debug("Failed to introspect meta-annotations on [" + element + "]: " + ex);
1621 1622 1623 1624 1625
			}
		}
		else {
			// Direct annotation lookup on regular Class, Method, Field
			if (loggerToUse.isInfoEnabled()) {
1626
				loggerToUse.info("Failed to introspect annotations on [" + element + "]: " + ex);
1627
			}
1628 1629 1630 1631
		}
	}


1632
	/**
1633
	 * Cache key for the AnnotatedElement cache.
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
	 */
	private static class AnnotationCacheKey {

		private final AnnotatedElement element;

		private final Class<? extends Annotation> annotationType;

		public AnnotationCacheKey(AnnotatedElement element, Class<? extends Annotation> annotationType) {
			this.element = element;
			this.annotationType = annotationType;
		}

		@Override
		public boolean equals(Object other) {
			if (this == other) {
				return true;
			}
			if (!(other instanceof AnnotationCacheKey)) {
				return false;
			}
			AnnotationCacheKey otherKey = (AnnotationCacheKey) other;
			return (this.element.equals(otherKey.element) &&
					ObjectUtils.nullSafeEquals(this.annotationType, otherKey.annotationType));
		}

		@Override
		public int hashCode() {
			return (this.element.hashCode() * 29 + this.annotationType.hashCode());
		}
	}


1666 1667 1668 1669
	private static class AnnotationCollector<A extends Annotation> {

		private final Class<A> annotationType;

S
Sam Brannen 已提交
1670 1671
		private final Class<? extends Annotation> containerAnnotationType;

1672 1673
		private final boolean declaredMode;

1674 1675 1676 1677
		private final Set<AnnotatedElement> visited = new HashSet<AnnotatedElement>();

		private final Set<A> result = new LinkedHashSet<A>();

1678

S
Sam Brannen 已提交
1679
		AnnotationCollector(Class<A> annotationType, Class<? extends Annotation> containerAnnotationType, boolean declaredMode) {
1680
			this.annotationType = annotationType;
S
Sam Brannen 已提交
1681
			this.containerAnnotationType = containerAnnotationType;
1682
			this.declaredMode = declaredMode;
1683 1684
		}

1685
		Set<A> getResult(AnnotatedElement element) {
1686 1687 1688 1689 1690
			process(element);
			return Collections.unmodifiableSet(this.result);
		}

		@SuppressWarnings("unchecked")
1691 1692 1693
		private void process(AnnotatedElement element) {
			if (this.visited.add(element)) {
				try {
S
Sam Brannen 已提交
1694
					Annotation[] annotations = (this.declaredMode ? element.getDeclaredAnnotations() : element.getAnnotations());
1695
					for (Annotation ann : annotations) {
1696 1697
						Class<? extends Annotation> currentAnnotationType = ann.annotationType();
						if (ObjectUtils.nullSafeEquals(this.annotationType, currentAnnotationType)) {
1698
							this.result.add(synthesizeAnnotation((A) ann, element));
1699
						}
1700
						else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) {
1701
							this.result.addAll(getValue(element, ann));
1702 1703
						}
						else if (!isInJavaLangAnnotationPackage(ann)) {
1704
							process(currentAnnotationType);
1705
						}
1706 1707
					}
				}
1708
				catch (Exception ex) {
1709
					handleIntrospectionFailure(element, ex);
1710
				}
1711 1712 1713 1714
			}
		}

		@SuppressWarnings("unchecked")
1715
		private List<A> getValue(AnnotatedElement element, Annotation annotation) {
1716 1717
			try {
				Method method = annotation.annotationType().getDeclaredMethod("value");
1718
				ReflectionUtils.makeAccessible(method);
1719 1720 1721 1722
				A[] annotations = (A[]) method.invoke(annotation);

				List<A> synthesizedAnnotations = new ArrayList<A>();
				for (A anno : annotations) {
1723
					synthesizedAnnotations.add(synthesizeAnnotation(anno, element));
1724 1725
				}
				return synthesizedAnnotations;
1726 1727
			}
			catch (Exception ex) {
1728
				handleIntrospectionFailure(element, ex);
1729
			}
1730 1731
			// Unable to read value from repeating annotation container -> ignore it.
			return Collections.emptyList();
1732 1733
		}
	}
J
Juergen Hoeller 已提交
1734

A
Arjen Poutsma 已提交
1735
}