AnnotationUtils.java 40.6 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;
A
Arjen Poutsma 已提交
21
import java.lang.reflect.Method;
22 23 24 25
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
26
import java.util.List;
A
Arjen Poutsma 已提交
27
import java.util.Map;
28
import java.util.Set;
A
Arjen Poutsma 已提交
29

30 31 32
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

A
Arjen Poutsma 已提交
33 34
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;
35
import org.springframework.util.ConcurrentReferenceHashMap;
36
import org.springframework.util.ObjectUtils;
37
import org.springframework.util.ReflectionUtils;
38
import org.springframework.util.StringUtils;
A
Arjen Poutsma 已提交
39 40

/**
41 42 43 44 45 46
 * 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 已提交
47
 *
S
Sam Brannen 已提交
48 49 50 51 52 53 54 55
 * <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 已提交
56
 *
57 58 59 60 61 62 63 64
 * <h3>Terminology</h3>
 * The terms <em>directly present</em> and <em>present</em> have the same
 * meanings as defined in the class-level Javadoc for {@link AnnotatedElement}.
 *
 * <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.
 *
65
 * <h3>Meta-annotation Support</h3>
66 67 68 69 70
 * <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.
71
 *
72 73 74 75 76 77
 * <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 已提交
78 79 80 81
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @author Mark Fisher
C
Chris Beams 已提交
82
 * @author Chris Beams
83
 * @author Phillip Webb
A
Arjen Poutsma 已提交
84
 * @since 2.0
85 86 87
 * @see java.lang.reflect.AnnotatedElement#getAnnotations()
 * @see java.lang.reflect.AnnotatedElement#getAnnotation(Class)
 * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotations()
A
Arjen Poutsma 已提交
88 89 90 91
 */
public abstract class AnnotationUtils {

	/** The attribute name for annotations with a single element */
92
	public static final String VALUE = "value";
A
Arjen Poutsma 已提交
93

94

95 96 97 98 99
	private static final Map<AnnotationCacheKey, Annotation> findAnnotationCache =
			new ConcurrentReferenceHashMap<AnnotationCacheKey, Annotation>(256);

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

101 102
	private static transient Log logger;

J
Juergen Hoeller 已提交
103

104 105
	/**
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied
106 107
	 * annotation: either the given annotation itself or a direct meta-annotation
	 * thereof.
108 109 110
	 * <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.
111
	 * @param ann the Annotation to check
J
Juergen Hoeller 已提交
112
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
113
	 * @return the first matching annotation, or {@code null} if not found
114 115 116
	 * @since 4.0
	 */
	@SuppressWarnings("unchecked")
117
	public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> annotationType) {
118
		if (annotationType.isInstance(ann)) {
119
			return (A) ann;
120
		}
121 122 123 124 125
		try {
			return ann.annotationType().getAnnotation(annotationType);
		}
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
126
			logIntrospectionFailure(ann.annotationType(), ex);
127 128
			return null;
		}
129 130
	}

131
	/**
C
Chris Beams 已提交
132
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied
133 134
	 * {@link AnnotatedElement}, where the annotation is either <em>present</em> or
	 * <em>meta-present</em> on the {@code AnnotatedElement}.
135 136 137
	 * <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.
138
	 * @param annotatedElement the {@code AnnotatedElement} from which to get the annotation
J
Juergen Hoeller 已提交
139
	 * @param annotationType the annotation type to look for, both locally and as a meta-annotation
140
	 * @return the first matching annotation, or {@code null} if not found
C
Chris Beams 已提交
141
	 * @since 3.1
142
	 */
143
	public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
144
		try {
145
			A ann = annotatedElement.getAnnotation(annotationType);
146
			if (ann == null) {
147
				for (Annotation metaAnn : annotatedElement.getAnnotations()) {
148 149 150 151
					ann = metaAnn.annotationType().getAnnotation(annotationType);
					if (ann != null) {
						break;
					}
152 153
				}
			}
154 155 156 157
			return ann;
		}
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
158
			logIntrospectionFailure(annotatedElement, ex);
159
			return null;
160 161 162
		}
	}

163
	/**
164
	 * Get a single {@link Annotation} of {@code annotationType} from the
165 166
	 * supplied {@link Method}, where the annotation is either <em>present</em>
	 * or <em>meta-present</em> on the method.
167
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
168 169 170
	 * <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.
171 172
	 * @param method the method to look for annotations on
	 * @param annotationType the annotation type to look for
173
	 * @return the first matching annotation, or {@code null} if not found
174 175 176 177 178 179 180 181 182 183 184 185
	 * @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.
186
	 * @param annotatedElement the Method, Constructor or Field to retrieve annotations from
187 188 189
	 * @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)
190 191 192 193 194 195 196 197 198 199
	 * @since 4.0.8
	 */
	public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
		try {
			return annotatedElement.getAnnotations();
		}
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
			logIntrospectionFailure(annotatedElement, ex);
		}
200
		return null;
201 202
	}

A
Arjen Poutsma 已提交
203
	/**
204 205
	 * Get all {@link Annotation Annotations} that are <em>present</em on the
	 * supplied {@link Method}.
A
Arjen Poutsma 已提交
206
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
207
	 * <p>Meta-annotations will <em>not</em> be searched.
208
	 * @param method the Method to retrieve annotations from
209 210 211
	 * @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 已提交
212
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
213
	 * @see AnnotatedElement#getAnnotations()
A
Arjen Poutsma 已提交
214 215
	 */
	public static Annotation[] getAnnotations(Method method) {
216 217 218 219 220
		try {
			return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
		}
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
221
			logIntrospectionFailure(method, ex);
222
		}
223
		return null;
A
Arjen Poutsma 已提交
224 225 226
	}

	/**
227 228 229 230 231
	 * Get the <em>repeatable</em> {@link Annotation}s of {@code annotationType}
	 * from the supplied {@link Method}, where such annotations are either
	 * <em>present</em> or <em>meta-present</em> on the method.
	 * <p>Handles both single annotations and annotations nested within a
	 * <em>containing annotation</em>.
232
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
233
	 * <p>Meta-annotations will be searched if the annotation is not
234 235 236 237
	 * <em>present</em> on the supplied method.
	 * @param method the method to look for annotations on; never {@code null}
	 * @param containerAnnotationType the type of the container that holds the
	 * annotations; may be {@code null} if a container is not supported
J
Juergen Hoeller 已提交
238
	 * @param annotationType the annotation type to look for
239
	 * @return the annotations found or an empty set; never {@code null}
240
	 * @since 4.0
J
Juergen Hoeller 已提交
241
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
242
	 * @see java.lang.annotation.Repeatable
243 244 245
	 */
	public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method method,
			Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
J
Juergen Hoeller 已提交
246

247
		Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
J
Juergen Hoeller 已提交
248
		return getRepeatableAnnotation((AnnotatedElement) resolvedMethod, containerAnnotationType, annotationType);
249 250 251
	}

	/**
252 253 254 255 256
	 * Get the <em>repeatable</em> {@link Annotation}s 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>Handles both single annotations and annotations nested within a
	 * <em>containing annotation</em>.
257
	 * <p>Meta-annotations will be searched if the annotation is not
258 259 260 261
	 * <em>present</em> on the supplied element.
	 * @param annotatedElement the element to look for annotations on; never {@code null}
	 * @param containerAnnotationType the type of the container that holds the
	 * annotations; may be {@code null} if a container is not supported
J
Juergen Hoeller 已提交
262
	 * @param annotationType the annotation type to look for
263
	 * @return the annotations found or an empty set; never {@code null}
264
	 * @since 4.0
265
	 * @see java.lang.annotation.Repeatable
266 267 268
	 */
	public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
			Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
J
Juergen Hoeller 已提交
269

270 271 272 273
		try {
			if (annotatedElement.getAnnotations().length > 0) {
				return new AnnotationCollector<A>(containerAnnotationType, annotationType).getResult(annotatedElement);
			}
274
		}
275 276
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
277
			logIntrospectionFailure(annotatedElement, ex);
278 279
		}
		return Collections.emptySet();
280 281
	}

A
Arjen Poutsma 已提交
282
	/**
283 284 285 286 287 288 289 290 291 292 293 294
	 * 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
295
	 * @return the first matching annotation, or {@code null} if not found
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	 * @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).
		return findAnnotation(annotatedElement, annotationType, new HashSet<Annotation>());
	}

	/**
	 * 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
311
	 * @return the first matching annotation, or {@code null} if not found
312 313 314
	 * @since 4.2
	 */
	@SuppressWarnings("unchecked")
315
	private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
316 317 318 319 320
		Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
		try {
			Annotation[] anns = annotatedElement.getDeclaredAnnotations();
			for (Annotation ann : anns) {
				if (ann.annotationType().equals(annotationType)) {
321
					return (A) ann;
322 323 324 325
				}
			}
			for (Annotation ann : anns) {
				if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
326
					A annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
					if (annotation != null) {
						return annotation;
					}
				}
			}
		}
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
			logIntrospectionFailure(annotatedElement, ex);
		}
		return null;
	}

	/**
	 * Find a single {@link Annotation} of {@code annotationType} on the supplied
J
Juergen Hoeller 已提交
342
	 * {@link Method}, traversing its super methods (i.e., from superclasses and
343 344
	 * interfaces) if the annotation is not <em>directly present</em> on the given
	 * method itself.
345 346 347
	 * <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 已提交
348 349
	 * <p>Annotations on methods are not inherited by default, so we need to handle
	 * this explicitly.
A
Arjen Poutsma 已提交
350
	 * @param method the method to look for annotations on
J
Juergen Hoeller 已提交
351
	 * @param annotationType the annotation type to look for
352
	 * @return the first matching annotation, or {@code null} if not found
353
	 * @see #getAnnotation(Method, Class)
A
Arjen Poutsma 已提交
354
	 */
355
	@SuppressWarnings("unchecked")
A
Arjen Poutsma 已提交
356
	public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
357 358
		AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
		A result = (A) findAnnotationCache.get(cacheKey);
359

360
		if (result == null) {
361 362 363
			Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
			result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);

364
			if (result == null) {
365
				result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
A
Arjen Poutsma 已提交
366
			}
367 368

			Class<?> clazz = method.getDeclaringClass();
369 370
			while (result == null) {
				clazz = clazz.getSuperclass();
371
				if (clazz == null || Object.class == clazz) {
372 373 374 375
					break;
				}
				try {
					Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
376 377
					Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
					result = findAnnotation((AnnotatedElement) resolvedEquivalentMethod, annotationType);
378 379 380 381 382 383 384
				}
				catch (NoSuchMethodException ex) {
					// No equivalent method found
				}
				if (result == null) {
					result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
				}
385
			}
386

387 388 389
			if (result != null) {
				findAnnotationCache.put(cacheKey, result);
			}
A
Arjen Poutsma 已提交
390
		}
391

392
		return result;
A
Arjen Poutsma 已提交
393 394
	}

395
	private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) {
396
		A annotation = null;
J
Juergen Hoeller 已提交
397
		for (Class<?> iface : ifcs) {
398 399 400 401 402 403 404 405 406 407 408
			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;
				}
409
			}
410 411 412 413
		}
		return annotation;
	}

414
	static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
415 416
		Boolean flag = annotatedInterfaceCache.get(iface);
		if (flag != null) {
417
			return flag.booleanValue();
418
		}
419
		Boolean found = Boolean.FALSE;
420 421 422
		for (Method ifcMethod : iface.getMethods()) {
			try {
				if (ifcMethod.getAnnotations().length > 0) {
423
					found = Boolean.TRUE;
424
					break;
425
				}
426 427 428
			}
			catch (Exception ex) {
				// Assuming nested Class values not resolvable within annotation attributes...
429
				logIntrospectionFailure(ifcMethod, ex);
430 431
			}
		}
432
		annotatedInterfaceCache.put(iface, found);
433
		return found.booleanValue();
434 435
	}

A
Arjen Poutsma 已提交
436
	/**
437 438
	 * Find a single {@link Annotation} of {@code annotationType} on the
	 * supplied {@link Class}, traversing its interfaces, annotations, and
439 440
	 * superclasses if the annotation is not <em>directly present</em> on
	 * the given class itself.
S
Sam Brannen 已提交
441
	 * <p>This method explicitly handles class-level annotations which are not
442 443
	 * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
	 * as meta-annotations and annotations on interfaces</em>.
S
Sam Brannen 已提交
444 445
	 * <p>The algorithm operates as follows:
	 * <ol>
446 447
	 * <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.
448
	 * <li>Recursively search through all interfaces that the given class declares.
449
	 * <li>Recursively search through the superclass hierarchy of the given class.
S
Sam Brannen 已提交
450
	 * </ol>
451 452 453
	 * <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 已提交
454
	 * @param clazz the class to look for annotations on
455
	 * @param annotationType the type of annotation to look for
456
	 * @return the first matching annotation, or {@code null} if not found
A
Arjen Poutsma 已提交
457
	 */
458
	@SuppressWarnings("unchecked")
A
Arjen Poutsma 已提交
459
	public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
460 461 462 463 464 465 466 467 468
		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);
			}
		}
		return result;
469 470 471 472 473
	}

	/**
	 * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
	 * avoiding endless recursion by tracking which annotations have already
S
Sam Brannen 已提交
474
	 * been <em>visited</em>.
475 476
	 * @param clazz the class to look for annotations on
	 * @param annotationType the type of annotation to look for
S
Sam Brannen 已提交
477
	 * @param visited the set of annotations that have already been visited
478
	 * @return the first matching annotation, or {@code null} if not found
479
	 */
480
	@SuppressWarnings("unchecked")
J
Juergen Hoeller 已提交
481
	private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
A
Arjen Poutsma 已提交
482
		Assert.notNull(clazz, "Class must not be null");
483 484 485 486 487 488 489

		try {
			Annotation[] anns = clazz.getDeclaredAnnotations();
			for (Annotation ann : anns) {
				if (ann.annotationType().equals(annotationType)) {
					return (A) ann;
				}
490
			}
491 492 493 494 495 496
			for (Annotation ann : anns) {
				if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
					A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
					if (annotation != null) {
						return annotation;
					}
497
				}
498
			}
A
Arjen Poutsma 已提交
499
		}
500 501
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
502
			logIntrospectionFailure(clazz, ex);
503 504 505
			return null;
		}

A
Arjen Poutsma 已提交
506
		for (Class<?> ifc : clazz.getInterfaces()) {
507
			A annotation = findAnnotation(ifc, annotationType, visited);
A
Arjen Poutsma 已提交
508 509 510 511
			if (annotation != null) {
				return annotation;
			}
		}
512

513
		Class<?> superclass = clazz.getSuperclass();
514
		if (superclass == null || Object.class == superclass) {
A
Arjen Poutsma 已提交
515 516
			return null;
		}
S
Sam Brannen 已提交
517
		return findAnnotation(superclass, annotationType, visited);
A
Arjen Poutsma 已提交
518 519 520
	}

	/**
521 522 523 524 525 526 527
	 * 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.
528
	 * <p>Meta-annotations will <em>not</em> be searched.
529 530 531 532 533 534 535 536
	 * <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 已提交
537 538
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
539 540
	 * @see #findAnnotationDeclaringClassForTypes(List, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
A
Arjen Poutsma 已提交
541 542 543
	 */
	public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
544
		if (clazz == null || Object.class == clazz) {
A
Arjen Poutsma 已提交
545 546
			return null;
		}
547 548 549 550
		if (isAnnotationDeclaredLocally(annotationType, clazz)) {
			return clazz;
		}
		return findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());
551 552 553
	}

	/**
554 555 556 557 558 559 560
	 * 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.
561
	 * <p>Meta-annotations will <em>not</em> be searched.
562 563 564 565 566 567 568 569
	 * <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
570
	 * {@code annotationTypes}, or {@code null} if not found
571
	 * @since 3.2.2
572 573 574 575 576
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
	 * @see #findAnnotationDeclaringClass(Class, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
	 */
577
	public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes, Class<?> clazz) {
578
		Assert.notEmpty(annotationTypes, "The list of annotation types must not be empty");
579
		if (clazz == null || Object.class == clazz) {
580 581 582 583 584 585 586 587
			return null;
		}
		for (Class<? extends Annotation> annotationType : annotationTypes) {
			if (isAnnotationDeclaredLocally(annotationType, clazz)) {
				return clazz;
			}
		}
		return findAnnotationDeclaringClassForTypes(annotationTypes, clazz.getSuperclass());
A
Arjen Poutsma 已提交
588 589 590
	}

	/**
591 592 593 594
	 * 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.
595
	 * <p>Meta-annotations will <em>not</em> be searched.
596 597 598
	 * <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 已提交
599
	 * {@link #isAnnotationInherited(Class, Class)} instead.
600 601
	 * @param annotationType the annotation type to look for
	 * @param clazz the class to check for the annotation on
602
	 * @return {@code true} if an annotation of the specified {@code annotationType}
603
	 * is <em>directly present</em>
604 605
	 * @see java.lang.Class#getDeclaredAnnotations()
	 * @see java.lang.Class#getDeclaredAnnotation(Class)
A
Arjen Poutsma 已提交
606 607 608 609 610
	 * @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");
611
		try {
612 613
			for (Annotation ann : clazz.getDeclaredAnnotations()) {
				if (ann.annotationType().equals(annotationType)) {
614
					return true;
615
				}
A
Arjen Poutsma 已提交
616 617
			}
		}
618 619
		catch (Exception ex) {
			// Assuming nested Class values not resolvable within annotation attributes...
620
			logIntrospectionFailure(clazz, ex);
621
		}
622
		return false;
A
Arjen Poutsma 已提交
623 624 625
	}

	/**
626 627 628 629
	 * 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>).
630
	 * <p>Meta-annotations will <em>not</em> be searched.
631 632 633 634 635 636 637 638 639 640
	 * <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 已提交
641 642 643 644 645 646 647 648 649
	 * @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));
	}

650
	/**
J
Juergen Hoeller 已提交
651
	 * Determine if the supplied {@link Annotation} is defined in the core JDK
652
	 * {@code java.lang.annotation} package.
J
Juergen Hoeller 已提交
653
	 * @param annotation the annotation to check (never {@code null})
654 655 656 657
	 * @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");
658 659 660 661 662 663 664 665 666 667 668 669 670
		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");
671 672
	}

A
Arjen Poutsma 已提交
673
	/**
J
Juergen Hoeller 已提交
674
	 * Retrieve the given annotation's attributes as a {@link Map}, preserving all
675 676 677 678
	 * 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 已提交
679 680
	 * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
	 * However, the {@code Map} signature has been preserved for binary compatibility.
A
Arjen Poutsma 已提交
681
	 * @param annotation the annotation to retrieve the attributes for
J
Juergen Hoeller 已提交
682
	 * @return the Map of annotation attributes, with attribute names as keys and
683 684
	 * corresponding attribute values as values; never {@code null}
	 * @see #getAnnotationAttributes(Annotation, boolean, boolean)
A
Arjen Poutsma 已提交
685 686
	 */
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
687
		return getAnnotationAttributes(annotation, false, false);
688 689 690
	}

	/**
691 692 693
	 * 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 已提交
694 695
	 * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
	 * However, the {@code Map} signature has been preserved for binary compatibility.
696
	 * @param annotation the annotation to retrieve the attributes for
697
	 * @param classValuesAsString whether to turn Class references into Strings (for
S
Sam Brannen 已提交
698
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
J
Juergen Hoeller 已提交
699
	 * or to preserve them as Class references
J
Juergen Hoeller 已提交
700
	 * @return the Map of annotation attributes, with attribute names as keys and
701 702
	 * corresponding attribute values as values; never {@code null}
	 * @see #getAnnotationAttributes(Annotation, boolean, boolean)
703
	 */
704
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {
705 706 707 708 709
		return getAnnotationAttributes(annotation, classValuesAsString, false);
	}

	/**
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes}
J
Juergen Hoeller 已提交
710 711 712
	 * map structure.
	 * <p>This method provides fully recursive annotation reading capabilities on par with
	 * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
713
	 * @param annotation the annotation to retrieve the attributes for
714
	 * @param classValuesAsString whether to convert Class references into Strings (for
S
Sam Brannen 已提交
715
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
J
Juergen Hoeller 已提交
716
	 * or to preserve them as Class references
717 718
	 * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
	 * {@link AnnotationAttributes} maps (for compatibility with
S
Sam Brannen 已提交
719
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
720 721
	 * Annotation instances
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
722
	 * and corresponding attribute values as values; never {@code null}
723 724
	 * @since 3.1.1
	 */
725 726
	public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString,
			boolean nestedAnnotationsAsMap) {
727 728

		AnnotationAttributes attrs = new AnnotationAttributes();
A
Arjen Poutsma 已提交
729
		Method[] methods = annotation.annotationType().getDeclaredMethods();
730
		for (Method method : methods) {
A
Arjen Poutsma 已提交
731 732
			if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {
				try {
733
					ReflectionUtils.makeAccessible(method);
734
					Object value = method.invoke(annotation);
735
					attrs.put(method.getName(), adaptValue(value, classValuesAsString, nestedAnnotationsAsMap));
A
Arjen Poutsma 已提交
736 737 738 739 740 741 742 743 744
				}
				catch (Exception ex) {
					throw new IllegalStateException("Could not obtain annotation attribute values", ex);
				}
			}
		}
		return attrs;
	}

745 746 747 748
	/**
	 * Adapt the given value according to the given class and nested annotation settings.
	 * @param value the annotation attribute value
	 * @param classValuesAsString whether to turn Class references into Strings (for
S
Sam Brannen 已提交
749
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
750 751 752
	 * or to preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
	 * {@link AnnotationAttributes} maps (for compatibility with
S
Sam Brannen 已提交
753
	 * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
754 755 756 757 758 759 760 761 762
	 * Annotation instances
	 * @return the adapted value, or the original value if no adaptation is needed
	 */
	static Object adaptValue(Object value, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
		if (classValuesAsString) {
			if (value instanceof Class) {
				value = ((Class<?>) value).getName();
			}
			else if (value instanceof Class[]) {
763
				Class<?>[] clazzArray = (Class<?>[]) value;
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
				String[] newValue = new String[clazzArray.length];
				for (int i = 0; i < clazzArray.length; i++) {
					newValue[i] = clazzArray[i].getName();
				}
				value = newValue;
			}
		}
		if (nestedAnnotationsAsMap && value instanceof Annotation) {
			return getAnnotationAttributes((Annotation) value, classValuesAsString, true);
		}
		else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
			Annotation[] realAnnotations = (Annotation[]) value;
			AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
			for (int i = 0; i < realAnnotations.length; i++) {
				mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString, true);
			}
			return mappedAnnotations;
		}
		else {
			return value;
		}
	}

A
Arjen Poutsma 已提交
787
	/**
788
	 * Retrieve the <em>value</em> of the {@code value} attribute of a
J
Juergen Hoeller 已提交
789
	 * single-element Annotation, given an annotation instance.
A
Arjen Poutsma 已提交
790
	 * @param annotation the annotation instance from which to retrieve the value
791
	 * @return the attribute value, or {@code null} if not found
A
Arjen Poutsma 已提交
792 793 794 795 796 797 798
	 * @see #getValue(Annotation, String)
	 */
	public static Object getValue(Annotation annotation) {
		return getValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
799
	 * Retrieve the <em>value</em> of a named attribute, given an annotation instance.
A
Arjen Poutsma 已提交
800 801
	 * @param annotation the annotation instance from which to retrieve the value
	 * @param attributeName the name of the attribute value to retrieve
802
	 * @return the attribute value, or {@code null} if not found
J
Juergen Hoeller 已提交
803
	 * @see #getValue(Annotation)
A
Arjen Poutsma 已提交
804 805
	 */
	public static Object getValue(Annotation annotation, String attributeName) {
806 807 808
		if (annotation == null || !StringUtils.hasLength(attributeName)) {
			return null;
		}
A
Arjen Poutsma 已提交
809
		try {
J
Juergen Hoeller 已提交
810
			Method method = annotation.annotationType().getDeclaredMethod(attributeName);
811
			ReflectionUtils.makeAccessible(method);
A
Arjen Poutsma 已提交
812 813 814 815 816 817 818 819
			return method.invoke(annotation);
		}
		catch (Exception ex) {
			return null;
		}
	}

	/**
820
	 * Retrieve the <em>default value</em> of the {@code value} attribute
J
Juergen Hoeller 已提交
821 822
	 * of a single-element Annotation, given an annotation instance.
	 * @param annotation the annotation instance from which to retrieve the default value
823
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
824 825 826 827 828 829 830
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Annotation annotation) {
		return getDefaultValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
831
	 * Retrieve the <em>default value</em> of a named attribute, given an annotation instance.
J
Juergen Hoeller 已提交
832
	 * @param annotation the annotation instance from which to retrieve the default value
A
Arjen Poutsma 已提交
833
	 * @param attributeName the name of the attribute value to retrieve
834
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
835 836 837
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Annotation annotation, String attributeName) {
838 839 840
		if (annotation == null) {
			return null;
		}
A
Arjen Poutsma 已提交
841 842 843 844
		return getDefaultValue(annotation.annotationType(), attributeName);
	}

	/**
845
	 * Retrieve the <em>default value</em> of the {@code value} attribute
J
Juergen Hoeller 已提交
846 847
	 * 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
848
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
849 850 851 852 853 854 855
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType) {
		return getDefaultValue(annotationType, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
856 857
	 * Retrieve the <em>default value</em> of a named attribute, given the
	 * {@link Class annotation type}.
J
Juergen Hoeller 已提交
858
	 * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
A
Arjen Poutsma 已提交
859
	 * @param attributeName the name of the attribute value to retrieve.
860
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
861 862 863
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
864 865 866
		if (annotationType == null || !StringUtils.hasLength(attributeName)) {
			return null;
		}
A
Arjen Poutsma 已提交
867
		try {
J
Juergen Hoeller 已提交
868
			return annotationType.getDeclaredMethod(attributeName).getDefaultValue();
A
Arjen Poutsma 已提交
869 870 871 872 873 874
		}
		catch (Exception ex) {
			return null;
		}
	}

875

876 877 878 879 880 881 882
	/**
	 * Log an introspection failure (in particular {@code TypeNotPresentExceptions}) -
	 * before moving on, pretending there were no annotations on this specific element.
	 * @param element the element that we tried to introspect annotations on
	 * @param ex the exception that we encountered
	 */
	static void logIntrospectionFailure(AnnotatedElement element, Exception ex) {
883 884 885 886 887
		Log loggerToUse = logger;
		if (loggerToUse == null) {
			loggerToUse = LogFactory.getLog(AnnotationUtils.class);
			logger = loggerToUse;
		}
888 889 890 891 892 893 894 895 896 897 898 899
		if (element instanceof Class && Annotation.class.isAssignableFrom((Class<?>) element)) {
			// Meta-annotation lookup on an annotation type
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to introspect meta-annotations on [" + element + "]: " + ex);
			}
		}
		else {
			// Direct annotation lookup on regular Class, Method, Field
			if (loggerToUse.isInfoEnabled()) {
				logger.info("Failed to introspect annotations on [" + element + "]: " + ex);
			}

900 901 902 903
		}
	}


904
	/**
905
	 * Cache key for the AnnotatedElement cache.
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
	 */
	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());
		}
	}


938 939 940 941 942 943 944 945 946 947
	private static class AnnotationCollector<A extends Annotation> {

		private final Class<? extends Annotation> containerAnnotationType;

		private final Class<A> annotationType;

		private final Set<AnnotatedElement> visited = new HashSet<AnnotatedElement>();

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

J
Juergen Hoeller 已提交
948
		public AnnotationCollector(Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
949 950 951 952 953 954 955 956 957 958
			this.containerAnnotationType = containerAnnotationType;
			this.annotationType = annotationType;
		}

		public Set<A> getResult(AnnotatedElement element) {
			process(element);
			return Collections.unmodifiableSet(this.result);
		}

		@SuppressWarnings("unchecked")
959 960 961 962
		private void process(AnnotatedElement element) {
			if (this.visited.add(element)) {
				try {
					for (Annotation ann : element.getAnnotations()) {
963 964
						Class<? extends Annotation> currentAnnotationType = ann.annotationType();
						if (ObjectUtils.nullSafeEquals(this.annotationType, currentAnnotationType)) {
965 966
							this.result.add((A) ann);
						}
967
						else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) {
968 969 970
							this.result.addAll(getValue(ann));
						}
						else if (!isInJavaLangAnnotationPackage(ann)) {
971
							process(currentAnnotationType);
972
						}
973 974
					}
				}
975 976 977
				catch (Exception ex) {
					logIntrospectionFailure(element, ex);
				}
978 979 980 981
			}
		}

		@SuppressWarnings("unchecked")
982
		private List<A> getValue(Annotation annotation) {
983 984
			try {
				Method method = annotation.annotationType().getDeclaredMethod("value");
985
				ReflectionUtils.makeAccessible(method);
986
				return Arrays.asList((A[]) method.invoke(annotation));
987 988
			}
			catch (Exception ex) {
989 990
				// Unable to read value from repeating annotation container -> ignore it.
				return Collections.emptyList();
991 992 993
			}
		}
	}
J
Juergen Hoeller 已提交
994

A
Arjen Poutsma 已提交
995
}