AnnotatedElementUtils.java 36.2 KB
Newer Older
1
/*
2
 * Copyright 2002-2015 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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;
import java.lang.reflect.AnnotatedElement;
21
import java.lang.reflect.Method;
22 23 24 25 26
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

27
import org.springframework.core.BridgeMethodResolver;
28
import org.springframework.util.Assert;
29 30 31 32
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

/**
33 34
 * General utility methods for finding annotations and meta-annotations on
 * {@link AnnotatedElement AnnotatedElements}.
35 36
 *
 * <p>{@code AnnotatedElementUtils} defines the public API for Spring's
37 38 39
 * meta-annotation programming model with support for <em>annotation attribute
 * overrides</em>. If you do not need support for annotation attribute
 * overrides, consider using {@link AnnotationUtils} instead.
40 41 42 43
 *
 * <p>Note that the features of this class are not provided by the JDK's
 * introspection facilities themselves.
 *
44
 * <h3>Annotation Attribute Overrides</h3>
45
 * <p>Support for meta-annotations with <em>attribute overrides</em> in
46
 * <em>composed annotations</em> is provided by all variants of the
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
 * {@code getAnnotationAttributes()} and {@code findAnnotationAttributes()}
 * methods.
 *
 * <h3>Find vs. Get Semantics</h3>
 * <p>The search algorithms used by methods in this class follow either
 * <em>find</em> or <em>get</em> semantics. Consult the Javadoc for each
 * individual method for details on which search algorithm is used.
 *
 * <p><strong>Get semantics</strong> are limited to searching for annotations
 * that are either <em>present</em> on an {@code AnnotatedElement} (i.e.,
 * declared locally or {@linkplain java.lang.annotation.Inherited inherited})
 * or declared within the annotation hierarchy above an {@code AnnotatedElement}.
 *
 * <p><strong>Find semantics</strong> are much more exhaustive, providing
 * <em>get semantics</em> plus support for the following:
 *
 * <ul>
 * <li>Searching on interfaces, if the annotated element is a class
 * <li>Searching on superclasses, if the annotated element is a class
 * <li>Resolving bridged methods, if the annotated element is a method
 * <li>Searching on methods in interfaces, if the annotated element is a method
 * <li>Searching on methods in superclasses, if the annotated element is a method
 * </ul>
70
 *
71 72 73 74 75 76 77
 * <h3>Support for {@code @Inherited}</h3>
 * <p>Methods following <em>get semantics</em> will honor the contract of
 * Java's {@link java.lang.annotation.Inherited @Inherited} annotation.
 * However, methods following <em>find semantics</em> will ignore the
 * presence of {@code @Inherited} since the <em>find</em> search algorithm
 * manually traverses type and method hierarchies and thereby implicitly
 * supports annotation inheritance without the need for {@code @Inherited}.
78 79 80
 *
 * @author Phillip Webb
 * @author Juergen Hoeller
81
 * @author Sam Brannen
82
 * @since 4.0
83 84 85
 * @see AnnotationUtils
 * @see AnnotationAttributes
 * @see BridgeMethodResolver
86 87 88
 */
public class AnnotatedElementUtils {

89 90 91
	private static final Boolean CONTINUE = null;


92
	/**
93
	 * Get the fully qualified class names of all meta-annotation
94
	 * types <em>present</em> on the annotation (of the specified
95 96
	 * {@code annotationType}) on the supplied {@link AnnotatedElement}.
	 *
97 98
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
99 100 101 102 103 104
	 *
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the annotation type on which to find
	 * meta-annotations; never {@code null}
	 * @return the names of all meta-annotations present on the annotation,
	 * or {@code null} if not found
S
Sam Brannen 已提交
105 106
	 * @see #getMetaAnnotationTypes(AnnotatedElement, String)
	 * @see #hasMetaAnnotationTypes
107 108 109 110 111 112 113 114
	 */
	public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
			Class<? extends Annotation> annotationType) {
		Assert.notNull(annotationType, "annotationType must not be null");
		return getMetaAnnotationTypes(element, annotationType.getName());
	}

	/**
115
	 * Get the fully qualified class names of all meta-annotation
116
	 * types <em>present</em> on the annotation (of the specified
117 118
	 * {@code annotationType}) on the supplied {@link AnnotatedElement}.
	 *
119 120
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
121
	 *
122 123
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
124 125 126
	 * type on which to find meta-annotations; never {@code null} or empty
	 * @return the names of all meta-annotations present on the annotation,
	 * or {@code null} if not found
S
Sam Brannen 已提交
127 128
	 * @see #getMetaAnnotationTypes(AnnotatedElement, Class)
	 * @see #hasMetaAnnotationTypes
129
	 */
130
	public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
131 132 133
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

134
		final Set<String> types = new LinkedHashSet<String>();
135

S
Sam Brannen 已提交
136 137 138
		try {
			Annotation annotation = getAnnotation(element, annotationType);
			if (annotation != null) {
139
				searchWithGetSemantics(annotation.annotationType(), annotationType, new SimpleAnnotationProcessor<Object>() {
S
Sam Brannen 已提交
140 141 142 143

					@Override
					public Object process(Annotation annotation, int metaDepth) {
						types.add(annotation.annotationType().getName());
144
						return CONTINUE;
S
Sam Brannen 已提交
145 146
					}
				}, new HashSet<AnnotatedElement>(), 1);
147
			}
S
Sam Brannen 已提交
148 149 150 151
		}
		catch (Throwable ex) {
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
		}
152

153 154 155
		return (types.isEmpty() ? null : types);
	}

156
	/**
S
Sam Brannen 已提交
157 158 159 160
	 * Determine if the supplied {@link AnnotatedElement} is annotated with
	 * a <em>composed annotation</em> that is meta-annotated with an
	 * annotation of the specified {@code annotationType}.
	 *
161 162
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
S
Sam Brannen 已提交
163
	 *
164
	 * @param element the annotated element; never {@code null}
S
Sam Brannen 已提交
165
	 * @param annotationType the fully qualified class name of the meta-annotation
166
	 * type to find; never {@code null} or empty
S
Sam Brannen 已提交
167 168
	 * @return {@code true} if a matching meta-annotation is present
	 * @see #getMetaAnnotationTypes
169
	 */
S
Sam Brannen 已提交
170
	public static boolean hasMetaAnnotationTypes(AnnotatedElement element, final String annotationType) {
171 172 173
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

174
		return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
175
			@Override
176
			public Boolean process(Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
177
				boolean found = annotation.annotationType().getName().equals(annotationType);
178
				return ((found && (metaDepth > 0)) ? Boolean.TRUE : CONTINUE);
179 180 181 182
			}
		}));
	}

183
	/**
S
Sam Brannen 已提交
184 185 186 187 188 189 190
	 * Determine if an annotation of the specified {@code annotationType}
	 * is <em>present</em> on the supplied {@link AnnotatedElement} or
	 * within the annotation hierarchy above the specified element.
	 *
	 * <p>If this method returns {@code true}, then {@link #getAnnotationAttributes}
	 * will return a non-null value.
	 *
191 192 193
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
	 *
194 195 196
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
S
Sam Brannen 已提交
197
	 * @return {@code true} if a matching annotation is present
198
	 */
S
Sam Brannen 已提交
199
	public static boolean isAnnotated(AnnotatedElement element, final String annotationType) {
200 201 202
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

203
		return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
204
			@Override
205
			public Boolean process(Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
206
				boolean found = annotation.annotationType().getName().equals(annotationType);
207
				return (found ? Boolean.TRUE : CONTINUE);
208 209 210 211
			}
		}));
	}

212
	/**
213 214
	 * Get annotation attributes of the specified {@code annotationType}
	 * in the annotation hierarchy of the supplied {@link AnnotatedElement}
215 216 217
	 * and merge the results into an {@link AnnotationAttributes} map.
	 *
	 * <p>Delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
218 219
	 * supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
	 *
220 221 222
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
	 *
223 224 225
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
226 227
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
228
	 * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
229 230
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
231
	 */
232 233 234 235
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType) {
		return getAnnotationAttributes(element, annotationType, false, false);
	}

236
	/**
237 238
	 * Get annotation attributes of the specified {@code annotationType}
	 * in the annotation hierarchy of the supplied {@link AnnotatedElement}
239
	 * and merge the results into an {@link AnnotationAttributes} map.
240
	 *
241 242 243
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
	 *
244 245 246
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
247 248
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
249 250 251
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
	 * instances into {@link AnnotationAttributes} maps or to preserve them
	 * as Annotation instances
252 253
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
254 255 256
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
257
	 */
258
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType,
259
			boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
260
		return searchWithGetSemantics(element, annotationType, new MergedAnnotationAttributesProcessor(annotationType,
261 262 263 264
			classValuesAsString, nestedAnnotationsAsMap));
	}

	/**
265 266 267 268
	 * Find annotation attributes of the specified {@code annotationType}
	 * within annotation hierarchies <em>above</em> the supplied
	 * {@link AnnotatedElement} and merge the results into an
	 * {@link AnnotationAttributes} map.
269
	 *
270 271
	 * <p>This method follows <em>find semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
272
	 *
273 274
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the annotation type to find; never {@code null}
275 276
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
277
	 * @since 4.2
278 279
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
280 281 282
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element,
			Class<? extends Annotation> annotationType) {
283
		Assert.notNull(annotationType, "annotationType must not be null");
284
		return findAnnotationAttributes(element, annotationType.getName());
285 286 287
	}

	/**
288 289 290 291
	 * Find annotation attributes of the specified {@code annotationType}
	 * within annotation hierarchies <em>above</em> the supplied
	 * {@link AnnotatedElement} and merge the results into an
	 * {@link AnnotationAttributes} map.
292
	 *
293 294
	 * <p>This method follows <em>find semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
295
	 *
296 297 298
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
299 300
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
301
	 * @since 4.2
302 303
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
304 305
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType) {
306
		return findAnnotationAttributes(element, annotationType, false, false);
307
	}
308

309
	/**
310 311 312 313
	 * Find annotation attributes of the specified {@code annotationType}
	 * within annotation hierarchies <em>above</em> the supplied
	 * {@link AnnotatedElement} and merge the results into an
	 * {@link AnnotationAttributes} map.
314
	 *
315 316
	 * <p>This method follows <em>find semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
317 318 319 320 321 322 323 324 325 326 327
	 *
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
	 * instances into {@link AnnotationAttributes} maps or to preserve them
	 * as Annotation instances
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
328
	 * @since 4.2
329 330 331
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
332 333 334 335 336 337 338
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
			boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
		return findAnnotationAttributes(element, annotationType, true, true, true, true, classValuesAsString,
			nestedAnnotationsAsMap);
	}

339
	/**
340 341 342 343
	 * Find annotation attributes of the specified {@code annotationType}
	 * within annotation hierarchies <em>above</em> the supplied
	 * {@link AnnotatedElement} and merge the results into an
	 * {@link AnnotationAttributes} map.
344
	 *
345 346 347
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
348
	 * @param searchOnInterfaces whether to search on interfaces, if the
349
	 * annotated element is a class
350 351 352 353 354 355
	 * @param searchOnSuperclasses whether to search on superclasses, if
	 * the annotated element is a class
	 * @param searchOnMethodsInInterfaces whether to search on methods in
	 * interfaces, if the annotated element is a method
	 * @param searchOnMethodsInSuperclasses whether to search on methods
	 * in superclasses, if the annotated element is a method
356 357
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
358 359 360
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
	 * instances into {@link AnnotationAttributes} maps or to preserve them
	 * as Annotation instances
361 362
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
363
	 * @since 4.2
364 365
	 * @see #searchWithFindSemantics
	 * @see MergedAnnotationAttributesProcessor
366
	 */
367
	private static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
368 369
			boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
			boolean searchOnMethodsInSuperclasses, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
370

371
		return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
372
			searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, new MergedAnnotationAttributesProcessor(
S
Sam Brannen 已提交
373
				annotationType, classValuesAsString, nestedAnnotationsAsMap));
374 375
	}

376
	/**
377
	 * Get the annotation attributes of <strong>all</strong> annotations
378 379 380 381 382
	 * of the specified {@code annotationType} in the annotation hierarchy above
	 * the supplied {@link AnnotatedElement} and store the results in a
	 * {@link MultiValueMap}.
	 *
	 * <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
383 384 385 386
	 * this method does <em>not</em> support attribute overrides.
	 *
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
387
	 *
388 389 390
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
391 392 393 394
	 * @return a {@link MultiValueMap} keyed by attribute name, containing
	 * the annotation attributes from all annotations found, or {@code null}
	 * if not found
	 * @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
395
	 */
396
	public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationType) {
397 398 399
		return getAllAnnotationAttributes(element, annotationType, false, false);
	}

400
	/**
401
	 * Get the annotation attributes of <strong>all</strong> annotations
402 403 404 405 406
	 * of the specified {@code annotationType} in the annotation hierarchy above
	 * the supplied {@link AnnotatedElement} and store the results in a
	 * {@link MultiValueMap}.
	 *
	 * <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
407 408 409 410
	 * this method does <em>not</em> support attribute overrides.
	 *
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
411
	 *
412 413 414
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
415 416 417 418 419
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
	 * instances into {@link AnnotationAttributes} maps or to preserve them
	 * as Annotation instances
420 421 422
	 * @return a {@link MultiValueMap} keyed by attribute name, containing
	 * the annotation attributes from all annotations found, or {@code null}
	 * if not found
423
	 */
424 425
	public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element,
			final String annotationType, final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
426

427 428
		final MultiValueMap<String, Object> attributesMap = new LinkedMultiValueMap<String, Object>();

429
		searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Void>() {
430

431
			@Override
432
			public Void process(Annotation annotation, int metaDepth) {
433 434 435 436 437 438
				boolean found = annotation.annotationType().getName().equals(annotationType);
				if (found) {
					AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes(annotation,
						classValuesAsString, nestedAnnotationsAsMap);
					for (Map.Entry<String, Object> entry : annotationAttributes.entrySet()) {
						attributesMap.add(entry.getKey(), entry.getValue());
439 440
					}
				}
441 442

				// Continue searching...
443 444 445
				return null;
			}
		});
446

447
		return (attributesMap.isEmpty() ? null : attributesMap);
448 449 450
	}

	/**
451 452
	 * Search for annotations of the specified {@code annotationType} on
	 * the specified {@code element}, following <em>get semantics</em>.
453
	 *
454 455 456
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
457
	 * @param processor the processor to delegate to
458
	 * @return the result of the processor, potentially {@code null}
459
	 */
460
	private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationType, Processor<T> processor) {
461
		try {
462
			return searchWithGetSemantics(element, annotationType, processor, new HashSet<AnnotatedElement>(), 0);
463 464
		}
		catch (Throwable ex) {
465
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
466 467 468 469
		}
	}

	/**
470
	 * Perform the search algorithm for the {@link #searchWithGetSemantics}
471 472 473
	 * method, avoiding endless recursion by tracking which annotated elements
	 * have already been <em>visited</em>.
	 *
474 475 476
	 * <p>The {@code metaDepth} parameter is explained in the
	 * {@link Processor#process process()} method of the {@link Processor}
	 * API.
477
	 *
478 479 480
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
481 482
	 * @param processor the processor to delegate to
	 * @param visited the set of annotated elements that have already been visited
483 484
	 * @param metaDepth the meta-depth of the annotation
	 * @return the result of the processor, potentially {@code null}
485
	 */
486
	private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationType,
487 488
			Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {

489 490 491
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

492 493 494 495 496 497 498
		if (visited.add(element)) {
			try {
				// Local annotations: declared OR inherited
				Annotation[] annotations = element.getAnnotations();

				// Search in local annotations
				for (Annotation annotation : annotations) {
499 500
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
							&& (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
501 502 503 504 505 506 507 508 509 510
						T result = processor.process(annotation, metaDepth);
						if (result != null) {
							return result;
						}
					}
				}

				// Search in meta annotations on local annotations
				for (Annotation annotation : annotations) {
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
511
						T result = searchWithGetSemantics(annotation.annotationType(), annotationType, processor,
S
Sam Brannen 已提交
512
							visited, metaDepth + 1);
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
						if (result != null) {
							processor.postProcess(annotation, result);
							return result;
						}
					}
				}

			}
			catch (Exception ex) {
				AnnotationUtils.logIntrospectionFailure(element, ex);
			}
		}
		return null;
	}

	/**
529 530
	 * Search for annotations of the specified {@code annotationType} on
	 * the specified {@code element}, following <em>find semantics</em>.
531
	 *
532 533 534
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
535
	 * @param searchOnInterfaces whether to search on interfaces, if the
536
	 * annotated element is a class
537 538 539 540 541 542
	 * @param searchOnSuperclasses whether to search on superclasses, if
	 * the annotated element is a class
	 * @param searchOnMethodsInInterfaces whether to search on methods in
	 * interfaces, if the annotated element is a method
	 * @param searchOnMethodsInSuperclasses whether to search on methods
	 * in superclasses, if the annotated element is a method
543
	 * @param processor the processor to delegate to
544
	 * @return the result of the processor, potentially {@code null}
545
	 */
546
	private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
547 548
			boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
			boolean searchOnMethodsInSuperclasses, Processor<T> processor) {
549 550

		try {
551
			return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
552
				searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor, new HashSet<AnnotatedElement>(), 0);
553 554
		}
		catch (Throwable ex) {
555
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
556
		}
557 558
	}

559
	/**
560
	 * Perform the search algorithm for the {@link #searchWithFindSemantics}
561 562
	 * method, avoiding endless recursion by tracking which annotated elements
	 * have already been <em>visited</em>.
563
	 *
564 565 566
	 * <p>The {@code metaDepth} parameter is explained in the
	 * {@link Processor#process process()} method of the {@link Processor}
	 * API.
567
	 *
568 569 570
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
571
	 * @param searchOnInterfaces whether to search on interfaces, if the
572
	 * annotated element is a class
573 574 575 576 577 578
	 * @param searchOnSuperclasses whether to search on superclasses, if
	 * the annotated element is a class
	 * @param searchOnMethodsInInterfaces whether to search on methods in
	 * interfaces, if the annotated element is a method
	 * @param searchOnMethodsInSuperclasses whether to search on methods
	 * in superclasses, if the annotated element is a method
579 580
	 * @param processor the processor to delegate to
	 * @param visited the set of annotated elements that have already been visited
581 582
	 * @param metaDepth the meta-depth of the annotation
	 * @return the result of the processor, potentially {@code null}
583
	 */
584
	private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
585 586
			boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
			boolean searchOnMethodsInSuperclasses, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
587

588 589 590
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

591
		if (visited.add(element)) {
592
			try {
593

594
				// Local annotations: declared or (declared + inherited).
595 596
				Annotation[] annotations = (searchOnSuperclasses ? element.getDeclaredAnnotations()
						: element.getAnnotations());
597 598

				// Search in local annotations
599
				for (Annotation annotation : annotations) {
600 601
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
							&& (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
602 603 604 605
						T result = processor.process(annotation, metaDepth);
						if (result != null) {
							return result;
						}
606 607
					}
				}
608

609
				// Search in meta annotations on local annotations
610 611
				for (Annotation annotation : annotations) {
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
612
						T result = searchWithFindSemantics(annotation.annotationType(), annotationType,
613
							searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
S
Sam Brannen 已提交
614
							searchOnMethodsInSuperclasses, processor, visited, metaDepth + 1);
615 616 617 618
						if (result != null) {
							processor.postProcess(annotation, result);
							return result;
						}
619
					}
620
				}
621

622 623 624 625 626
				if (element instanceof Method) {
					Method method = (Method) element;

					// Search on possibly bridged method
					Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
627
					T result = searchWithFindSemantics(resolvedMethod, annotationType, searchOnInterfaces,
628 629 630 631 632 633 634 635 636 637 638 639
						searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
						visited, metaDepth);
					if (result != null) {
						return result;
					}

					// Search on methods in interfaces declared locally
					if (searchOnMethodsInInterfaces) {
						Class<?>[] ifcs = method.getDeclaringClass().getInterfaces();
						result = searchOnInterfaces(method, annotationType, searchOnInterfaces, searchOnSuperclasses,
							searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor, visited, metaDepth,
							ifcs);
640 641 642 643
						if (result != null) {
							return result;
						}
					}
644 645 646 647 648 649 650 651 652 653 654 655 656 657

					// Search on methods in class hierarchy and interface hierarchy
					if (searchOnMethodsInSuperclasses) {
						Class<?> clazz = method.getDeclaringClass();
						while (true) {
							clazz = clazz.getSuperclass();
							if (clazz == null || clazz.equals(Object.class)) {
								break;
							}

							try {
								Method equivalentMethod = clazz.getDeclaredMethod(method.getName(),
									method.getParameterTypes());
								Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
658
								result = searchWithFindSemantics(resolvedEquivalentMethod, annotationType,
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
									searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
									searchOnMethodsInSuperclasses, processor, visited, metaDepth);
								if (result != null) {
									return result;
								}
							}
							catch (NoSuchMethodException ex) {
								// No equivalent method found
							}

							// Search on interfaces declared on superclass
							if (searchOnMethodsInInterfaces) {
								result = searchOnInterfaces(method, annotationType, searchOnInterfaces,
									searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
									processor, visited, metaDepth, clazz.getInterfaces());
								if (result != null) {
									return result;
								}
							}
						}
					}
680 681
				}

682 683 684 685 686 687
				if (element instanceof Class) {
					Class<?> clazz = (Class<?>) element;

					// Search on interfaces
					if (searchOnInterfaces) {
						for (Class<?> ifc : clazz.getInterfaces()) {
688
							T result = searchWithFindSemantics(ifc, annotationType, searchOnInterfaces,
689 690 691 692 693 694 695 696 697 698 699 700
								searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
								processor, visited, metaDepth);
							if (result != null) {
								return result;
							}
						}
					}

					// Search on superclass
					if (searchOnSuperclasses) {
						Class<?> superclass = clazz.getSuperclass();
						if (superclass != null && !superclass.equals(Object.class)) {
701
							T result = searchWithFindSemantics(superclass, annotationType, searchOnInterfaces,
702 703 704 705 706
								searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
								processor, visited, metaDepth);
							if (result != null) {
								return result;
							}
707
						}
708 709 710
					}
				}
			}
711 712 713
			catch (Exception ex) {
				AnnotationUtils.logIntrospectionFailure(element, ex);
			}
714 715 716 717
		}
		return null;
	}

718 719 720 721 722 723 724 725
	private static <T> T searchOnInterfaces(Method method, String annotationType, boolean searchOnInterfaces,
			boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces, boolean searchOnMethodsInSuperclasses,
			Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth, Class<?>[] ifcs) {

		for (Class<?> iface : ifcs) {
			if (AnnotationUtils.isInterfaceWithAnnotatedMethods(iface)) {
				try {
					Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
726
					T result = searchWithFindSemantics(equivalentMethod, annotationType, searchOnInterfaces,
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
						searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
						visited, metaDepth);

					if (result != null) {
						return result;
					}
				}
				catch (NoSuchMethodException ex) {
					// Skip this interface - it doesn't have the method...
				}
			}
		}

		return null;
	}

S
Sam Brannen 已提交
743 744 745 746 747 748 749 750
	private static Annotation getAnnotation(AnnotatedElement element, String annotationType) {
		for (Annotation annotation : element.getAnnotations()) {
			if (annotation.annotationType().getName().equals(annotationType)) {
				return annotation;
			}
		}
		return null;
	}
751

752

753
	/**
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
	 * Callback interface that is used to process annotations during a search.
	 *
	 * <p>Depending on the use case, a processor may choose to
	 * {@linkplain #process} a single target annotation, multiple target
	 * annotations, or all annotations discovered by the currently executing
	 * search. The term "target" in this context refers to a matching
	 * annotation (i.e., a specific annotation type that was found during
	 * the search). Returning a non-null value from the {@link #process}
	 * method instructs the search algorithm to stop searching further;
	 * whereas, returning {@code null} from the {@link #process} method
	 * instructs the search algorithm to continue searching for additional
	 * annotations.
	 *
	 * <p>Processors can optionally {@linkplain #postProcess post-process}
	 * the result of the {@link #process} method as the search algorithm
	 * goes back down the annotation hierarchy from an invocation of
	 * {@link #process} that returned a non-null value down to the
	 * {@link AnnotatedElement} that was supplied as the starting point to
	 * the search algorithm.
773
	 *
774
	 * @param <T> the type of result returned by the processor
775
	 */
776
	private static interface Processor<T> {
777 778

		/**
779 780 781 782 783 784 785 786 787
		 * Process the supplied annotation.
		 *
		 * <p>Depending on the use case, the supplied annotation may be an
		 * actual target annotation that has been found by the search
		 * algorithm, or it may be some other annotation within the
		 * annotation hierarchy. In the latter case, the {@code metaDepth}
		 * should have a value greater than {@code 0}. In any case, it is
		 * up to concrete implementations of this method to decide what to
		 * do with the supplied annotation.
788
		 *
789
		 * <p>The {@code metaDepth} parameter represents the depth of the
790 791 792 793 794
		 * annotation relative to the first annotated element in the
		 * annotation hierarchy. For example, an annotation that is
		 * <em>present</em> on a non-annotation element will have a depth
		 * of 0; a meta-annotation will have a depth of 1; and a
		 * meta-meta-annotation will have a depth of 2; etc.
795
		 *
796
		 * @param annotation the annotation to process
797
		 * @param metaDepth the meta-depth of the annotation
798
		 * @return the result of the processing, or {@code null} to continue
799
		 * searching for additional annotations
800
		 */
801
		T process(Annotation annotation, int metaDepth);
802

803 804 805 806
		/**
		 * Post-process the result returned by the {@link #process} method.
		 *
		 * <p>The {@code annotation} supplied to this method is an annotation
807
		 * that is present in the annotation hierarchy, between the initial
808 809
		 * {@link AnnotatedElement} and an invocation of {@link #process}
		 * that returned a non-null value.
810 811 812 813
		 *
		 * @param annotation the annotation to post-process
		 * @param result the result to post-process
		 */
814 815 816
		void postProcess(Annotation annotation, T result);
	}

817
	/**
818 819
	 * {@link Processor} that {@linkplain #process processes} annotations
	 * but does not {@link #postProcess} results.
820 821 822 823 824 825 826 827 828 829 830 831 832
	 * @since 4.2
	 */
	private abstract static class SimpleAnnotationProcessor<T> implements Processor<T> {

		/**
		 * <em>No-op</em>.
		 */
		@Override
		public final void postProcess(Annotation annotation, T result) {
			/* no-op */
		}
	}

833 834 835 836 837 838 839 840
	/**
	 * {@link Processor} that gets the {@code AnnotationAttributes} for the
	 * target annotation during the {@link #process} phase and then merges
	 * annotation attributes from lower levels in the annotation hierarchy
	 * during the {@link #postProcess} phase.
	 * @see AnnotationUtils#getAnnotationAttributes(Annotation)
	 * @since 4.2
	 */
841
	private static class MergedAnnotationAttributesProcessor implements Processor<AnnotationAttributes> {
842

S
Sam Brannen 已提交
843
		private final String annotationType;
844 845 846 847
		private final boolean classValuesAsString;
		private final boolean nestedAnnotationsAsMap;


848
		MergedAnnotationAttributesProcessor(String annotationType, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
S
Sam Brannen 已提交
849
			this.annotationType = annotationType;
850 851 852 853 854 855
			this.classValuesAsString = classValuesAsString;
			this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
		}

		@Override
		public AnnotationAttributes process(Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
856
			boolean found = annotation.annotationType().getName().equals(annotationType);
857
			return (found ? AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap) : null);
858 859 860
		}

		@Override
861 862
		public void postProcess(Annotation annotation, AnnotationAttributes attributes) {
			for (String key : attributes.keySet()) {
863 864 865
				if (!AnnotationUtils.VALUE.equals(key)) {
					Object value = AnnotationUtils.getValue(annotation, key);
					if (value != null) {
866
						attributes.put(key, AnnotationUtils.adaptValue(value, classValuesAsString, nestedAnnotationsAsMap));
867 868 869 870 871 872
					}
				}
			}
		}
	}

873
}