AnnotatedElementUtils.java 41.6 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
import java.util.ArrayList;
import java.util.Arrays;
24 25
import java.util.HashSet;
import java.util.LinkedHashSet;
26
import java.util.List;
27 28 29
import java.util.Map;
import java.util.Set;

30
import org.springframework.core.BridgeMethodResolver;
31
import org.springframework.util.Assert;
32 33
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
34 35
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
36 37

/**
38 39
 * General utility methods for finding annotations and meta-annotations on
 * {@link AnnotatedElement AnnotatedElements}.
40 41
 *
 * <p>{@code AnnotatedElementUtils} defines the public API for Spring's
42 43 44
 * 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.
45 46 47 48
 *
 * <p>Note that the features of this class are not provided by the JDK's
 * introspection facilities themselves.
 *
49
 * <h3>Annotation Attribute Overrides</h3>
50
 * <p>Support for meta-annotations with <em>attribute overrides</em> in
51
 * <em>composed annotations</em> is provided by all variants of the
52 53 54 55 56 57 58 59 60 61 62
 * {@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})
63 64
 * or declared within the annotation hierarchy <em>above</em> an
 * {@code AnnotatedElement}.
65 66 67 68 69 70 71 72 73 74 75
 *
 * <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>
76
 *
77 78
 * <h3>Support for {@code @Inherited}</h3>
 * <p>Methods following <em>get semantics</em> will honor the contract of
79 80 81 82 83 84 85
 * Java's {@link java.lang.annotation.Inherited @Inherited} annotation except
 * that locally declared annotations (including custom composed annotations)
 * will be favored over inherited annotations. In contrast, methods following
 * <em>find semantics</em> will completely 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}.
86 87 88
 *
 * @author Phillip Webb
 * @author Juergen Hoeller
89
 * @author Sam Brannen
90
 * @since 4.0
S
Sam Brannen 已提交
91
 * @see AliasFor
92
 * @see AnnotationAttributes
S
Sam Brannen 已提交
93
 * @see AnnotationUtils
94
 * @see BridgeMethodResolver
95 96 97
 */
public class AnnotatedElementUtils {

98 99 100
	private static final Boolean CONTINUE = null;


101
	/**
102
	 * Get the fully qualified class names of all meta-annotation
103
	 * types <em>present</em> on the annotation (of the specified
104 105
	 * {@code annotationType}) on the supplied {@link AnnotatedElement}.
	 *
106 107
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
108 109 110 111 112 113
	 *
	 * @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 已提交
114 115
	 * @see #getMetaAnnotationTypes(AnnotatedElement, String)
	 * @see #hasMetaAnnotationTypes
116 117 118 119 120 121 122 123
	 */
	public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
			Class<? extends Annotation> annotationType) {
		Assert.notNull(annotationType, "annotationType must not be null");
		return getMetaAnnotationTypes(element, annotationType.getName());
	}

	/**
124
	 * Get the fully qualified class names of all meta-annotation
125
	 * types <em>present</em> on the annotation (of the specified
126 127
	 * {@code annotationType}) on the supplied {@link AnnotatedElement}.
	 *
128 129
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
130
	 *
131 132
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
133 134 135
	 * 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 已提交
136 137
	 * @see #getMetaAnnotationTypes(AnnotatedElement, Class)
	 * @see #hasMetaAnnotationTypes
138
	 */
139
	public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
140 141 142
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

143
		final Set<String> types = new LinkedHashSet<String>();
144

S
Sam Brannen 已提交
145 146 147
		try {
			Annotation annotation = getAnnotation(element, annotationType);
			if (annotation != null) {
148
				searchWithGetSemantics(annotation.annotationType(), annotationType, new SimpleAnnotationProcessor<Object>() {
S
Sam Brannen 已提交
149 150

					@Override
151
					public Object process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
152
						types.add(annotation.annotationType().getName());
153
						return CONTINUE;
S
Sam Brannen 已提交
154 155
					}
				}, new HashSet<AnnotatedElement>(), 1);
156
			}
S
Sam Brannen 已提交
157 158
		}
		catch (Throwable ex) {
159
			AnnotationUtils.rethrowAnnotationConfigurationException(ex);
S
Sam Brannen 已提交
160 161
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
		}
162

163 164 165
		return (types.isEmpty() ? null : types);
	}

166
	/**
S
Sam Brannen 已提交
167 168 169 170
	 * 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}.
	 *
171 172
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
S
Sam Brannen 已提交
173
	 *
174
	 * @param element the annotated element; never {@code null}
S
Sam Brannen 已提交
175
	 * @param annotationType the fully qualified class name of the meta-annotation
176
	 * type to find; never {@code null} or empty
S
Sam Brannen 已提交
177 178
	 * @return {@code true} if a matching meta-annotation is present
	 * @see #getMetaAnnotationTypes
179
	 */
S
Sam Brannen 已提交
180
	public static boolean hasMetaAnnotationTypes(AnnotatedElement element, final String annotationType) {
181 182 183
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

184
		return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
185
			@Override
186
			public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
187
				boolean found = annotation.annotationType().getName().equals(annotationType);
188
				return ((found && (metaDepth > 0)) ? Boolean.TRUE : CONTINUE);
189 190 191 192
			}
		}));
	}

193
	/**
S
Sam Brannen 已提交
194 195
	 * Determine if an annotation of the specified {@code annotationType}
	 * is <em>present</em> on the supplied {@link AnnotatedElement} or
196
	 * within the annotation hierarchy <em>above</em> the specified element.
S
Sam Brannen 已提交
197 198 199 200
	 *
	 * <p>If this method returns {@code true}, then {@link #getAnnotationAttributes}
	 * will return a non-null value.
	 *
201 202 203
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
	 *
204 205 206
	 * @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 已提交
207
	 * @return {@code true} if a matching annotation is present
208
	 */
S
Sam Brannen 已提交
209
	public static boolean isAnnotated(AnnotatedElement element, final String annotationType) {
210 211 212
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

213
		return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
214
			@Override
215
			public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
S
Sam Brannen 已提交
216
				boolean found = annotation.annotationType().getName().equals(annotationType);
217
				return (found ? Boolean.TRUE : CONTINUE);
218 219 220 221
			}
		}));
	}

222
	/**
223 224 225 226
	 * Get the first annotation of the specified {@code annotationType} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
227
	 *
228
	 * <p>This method delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
229 230
	 * supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
	 *
231 232 233
	 * @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
234 235
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
236
	 * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
237 238
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
239
	 * @see #getAllAnnotationAttributes(AnnotatedElement, String)
240
	 */
241 242 243 244
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType) {
		return getAnnotationAttributes(element, annotationType, false, false);
	}

245
	/**
246 247 248 249 250 251 252 253 254 255 256 257 258
	 * Get the first annotation of the specified {@code annotationType} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
	 *
	 * <p>Attributes from lower levels in the annotation hierarchy override
	 * attributes of the same name from higher levels.
	 *
	 * <p>In contrast to {@link #getAllAnnotationAttributes}, the search
	 * algorithm used by this method will stop searching the annotation
	 * hierarchy once the first annotation of the specified
	 * {@code annotationType} has been found. As a consequence, additional
	 * annotations of the specified {@code annotationType} will be ignored.
259
	 *
260 261 262
	 * <p>This method follows <em>get semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
	 *
263 264 265
	 * @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
266 267
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
268
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
269
	 * instances into {@code AnnotationAttributes} maps or to preserve them
270
	 * as Annotation instances
271 272
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
273 274 275
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
276
	 * @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
277
	 */
278
	public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType,
279
			boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
280 281 282 283 284 285

		AnnotationAttributes attributes = searchWithGetSemantics(element, annotationType,
			new MergedAnnotationAttributesProcessor(annotationType, classValuesAsString, nestedAnnotationsAsMap));
		AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString,
			nestedAnnotationsAsMap);
		return attributes;
286 287 288
	}

	/**
289 290 291 292
	 * Find the first annotation of the specified {@code annotationType} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
293
	 *
294 295
	 * <p>This method delegates to {@link #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)}
	 * supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
296
	 *
297 298
	 * @param element the annotated element; never {@code null}
	 * @param annotationType the annotation type to find; never {@code null}
299 300
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
301
	 * @since 4.2
302 303
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
304 305 306
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element,
			Class<? extends Annotation> annotationType) {
307
		Assert.notNull(annotationType, "annotationType must not be null");
308
		return findAnnotationAttributes(element, annotationType.getName());
309 310 311
	}

	/**
312 313 314 315
	 * Find the first annotation of the specified {@code annotationType} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
316
	 *
317 318
	 * <p>This method delegates to {@link #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)}
	 * supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
319
	 *
320 321 322
	 * @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
323 324
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
325
	 * @since 4.2
326 327
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
328 329
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType) {
330
		return findAnnotationAttributes(element, annotationType, false, false);
331
	}
332

333
	/**
334 335 336 337 338 339 340 341 342 343 344 345 346
	 * Find the first annotation of the specified {@code annotationType} within
	 * the annotation hierarchy <em>above</em> the supplied {@code element} and
	 * merge that annotation's attributes with <em>matching</em> attributes from
	 * annotations in lower levels of the annotation hierarchy.
	 *
	 * <p>Attributes from lower levels in the annotation hierarchy override
	 * attributes of the same name from higher levels.
	 *
	 * <p>In contrast to {@link #getAllAnnotationAttributes}, the search
	 * algorithm used by this method will stop searching the annotation
	 * hierarchy once the first annotation of the specified
	 * {@code annotationType} has been found. As a consequence, additional
	 * annotations of the specified {@code annotationType} will be ignored.
347
	 *
348 349
	 * <p>This method follows <em>find semantics</em> as described in the
	 * {@linkplain AnnotatedElementUtils class-level Javadoc}.
350 351 352 353 354 355 356
	 *
	 * @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
357
	 * instances into {@code AnnotationAttributes} maps or to preserve them
358 359 360
	 * as Annotation instances
	 * @return the merged {@code AnnotationAttributes}, or {@code null} if
	 * not found
361
	 * @since 4.2
362 363 364
	 * @see #findAnnotationAttributes(AnnotatedElement, Class)
	 * @see #findAnnotationAttributes(AnnotatedElement, String)
	 * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
365 366 367
	 */
	public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
			boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
368 369 370 371 372 373

		AnnotationAttributes attributes = searchWithFindSemantics(element, annotationType,
			new MergedAnnotationAttributesProcessor(annotationType, classValuesAsString, nestedAnnotationsAsMap));
		AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString,
			nestedAnnotationsAsMap);
		return attributes;
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
	 * @param classValuesAsString whether to convert Class references into
	 * Strings or to preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to convert nested Annotation
418
	 * instances into {@code AnnotationAttributes} maps or to preserve them
419
	 * 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(AnnotatedElement annotatedElement, 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
			AnnotationUtils.rethrowAnnotationConfigurationException(ex);
466
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
467 468 469 470
		}
	}

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

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

493 494
		if (visited.add(element)) {
			try {
495 496 497

				// Start searching within locally declared annotations
				List<Annotation> declaredAnnotations = Arrays.asList(element.getDeclaredAnnotations());
498 499
				T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, annotationType, processor,
					visited, metaDepth);
500 501
				if (result != null) {
					return result;
502 503
				}

504 505 506 507
				List<Annotation> inheritedAnnotations = new ArrayList<Annotation>();
				for (Annotation annotation : element.getAnnotations()) {
					if (!declaredAnnotations.contains(annotation)) {
						inheritedAnnotations.add(annotation);
508 509 510
					}
				}

511
				// Continue searching within inherited annotations
512 513
				result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations, annotationType, processor,
					visited, metaDepth);
514 515 516
				if (result != null) {
					return result;
				}
517 518
			}
			catch (Exception ex) {
519
				AnnotationUtils.handleIntrospectionFailure(element, ex);
520 521
			}
		}
522

523 524 525
		return null;
	}

526 527 528 529 530 531 532 533 534 535 536 537
	/**
	 * This method is invoked by
	 * {@link #searchWithGetSemantics(AnnotatedElement, String, Processor, Set, int)}
	 * to perform the actual search within the supplied list of annotations.
	 * <p>This method should be invoked first with locally declared annotations
	 * and then subsequently with inherited annotations, thereby allowing
	 * local annotations to take precedence over inherited annotations.
	 *
	 * <p>The {@code metaDepth} parameter is explained in the
	 * {@link Processor#process process()} method of the {@link Processor}
	 * API.
	 *
538 539
	 * @param annotatedElement the element that is annotated with the supplied
	 * annotations, used for contextual logging; may be {@code null} if unknown
540 541 542 543 544 545 546 547
	 * @param annotations the annotations to search in; never {@code null}
	 * @param annotationType the fully qualified class name of the annotation
	 * type to find; never {@code null} or empty
	 * @param processor the processor to delegate to
	 * @param visited the set of annotated elements that have already been visited
	 * @param metaDepth the meta-depth of the annotation
	 * @return the result of the processor, potentially {@code null}
	 */
548 549 550
	private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annotatedElement,
			List<Annotation> annotations, String annotationType, Processor<T> processor, Set<AnnotatedElement> visited,
			int metaDepth) {
551 552 553 554 555

		// Search in annotations
		for (Annotation annotation : annotations) {
			if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
					&& (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
556
				T result = processor.process(annotatedElement, annotation, metaDepth);
557 558 559 560 561 562 563 564 565 566 567 568
				if (result != null) {
					return result;
				}
			}
		}

		// Recursively search in meta-annotations
		for (Annotation annotation : annotations) {
			if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
				T result = searchWithGetSemantics(annotation.annotationType(), annotationType, processor, visited,
					metaDepth + 1);
				if (result != null) {
569
					processor.postProcess(annotatedElement, annotation, result);
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
					return result;
				}
			}
		}

		return null;
	}

	/**
	 * Search for annotations of the specified {@code annotationType} on
	 * the specified {@code element}, following <em>find semantics</em>.
	 *
	 * @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 processor the processor to delegate to
	 * @return the result of the processor, potentially {@code null}
	 */
	private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType, Processor<T> processor) {
		return searchWithFindSemantics(element, annotationType, true, true, true, true, processor);
	}

592
	/**
593 594
	 * Search for annotations of the specified {@code annotationType} on
	 * the specified {@code element}, following <em>find semantics</em>.
595
	 *
596 597 598
	 * @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
599
	 * @param searchOnInterfaces whether to search on interfaces, if the
600
	 * annotated element is a class
601 602 603 604 605 606
	 * @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
607
	 * @param processor the processor to delegate to
608
	 * @return the result of the processor, potentially {@code null}
609
	 */
610
	private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
611 612
			boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
			boolean searchOnMethodsInSuperclasses, Processor<T> processor) {
613 614

		try {
615
			return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
616
				searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor, new HashSet<AnnotatedElement>(), 0);
617 618
		}
		catch (Throwable ex) {
619
			AnnotationUtils.rethrowAnnotationConfigurationException(ex);
620
			throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
621
		}
622 623
	}

624
	/**
625
	 * Perform the search algorithm for the {@link #searchWithFindSemantics}
626 627
	 * method, avoiding endless recursion by tracking which annotated elements
	 * have already been <em>visited</em>.
628
	 *
629 630 631
	 * <p>The {@code metaDepth} parameter is explained in the
	 * {@link Processor#process process()} method of the {@link Processor}
	 * API.
632
	 *
633 634 635
	 * @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
636
	 * @param searchOnInterfaces whether to search on interfaces, if the
637
	 * annotated element is a class
638 639 640 641 642 643
	 * @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
644 645
	 * @param processor the processor to delegate to
	 * @param visited the set of annotated elements that have already been visited
646 647
	 * @param metaDepth the meta-depth of the annotation
	 * @return the result of the processor, potentially {@code null}
648
	 */
649
	private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
650 651
			boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
			boolean searchOnMethodsInSuperclasses, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
652

653 654 655
		Assert.notNull(element, "AnnotatedElement must not be null");
		Assert.hasText(annotationType, "annotationType must not be null or empty");

656
		if (visited.add(element)) {
657
			try {
658

659
				// Local annotations: declared or (declared + inherited).
660 661
				Annotation[] annotations = (searchOnSuperclasses ? element.getDeclaredAnnotations()
						: element.getAnnotations());
662 663

				// Search in local annotations
664
				for (Annotation annotation : annotations) {
665 666
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
							&& (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
667
						T result = processor.process(element, annotation, metaDepth);
668 669 670
						if (result != null) {
							return result;
						}
671 672
					}
				}
673

674
				// Search in meta annotations on local annotations
675 676
				for (Annotation annotation : annotations) {
					if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
677
						T result = searchWithFindSemantics(annotation.annotationType(), annotationType,
678
							searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
S
Sam Brannen 已提交
679
							searchOnMethodsInSuperclasses, processor, visited, metaDepth + 1);
680
						if (result != null) {
681
							processor.postProcess(annotation.annotationType(), annotation, result);
682 683
							return result;
						}
684
					}
685
				}
686

687 688 689 690 691
				if (element instanceof Method) {
					Method method = (Method) element;

					// Search on possibly bridged method
					Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
692
					T result = searchWithFindSemantics(resolvedMethod, annotationType, searchOnInterfaces,
693 694 695 696 697 698 699 700 701 702 703 704
						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);
705 706 707 708
						if (result != null) {
							return result;
						}
					}
709 710 711 712 713 714

					// Search on methods in class hierarchy and interface hierarchy
					if (searchOnMethodsInSuperclasses) {
						Class<?> clazz = method.getDeclaringClass();
						while (true) {
							clazz = clazz.getSuperclass();
715
							if (clazz == null || Object.class == clazz) {
716 717 718 719 720 721 722
								break;
							}

							try {
								Method equivalentMethod = clazz.getDeclaredMethod(method.getName(),
									method.getParameterTypes());
								Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
723
								result = searchWithFindSemantics(resolvedEquivalentMethod, annotationType,
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
									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;
								}
							}
						}
					}
745 746
				}

747 748 749 750 751 752
				if (element instanceof Class) {
					Class<?> clazz = (Class<?>) element;

					// Search on interfaces
					if (searchOnInterfaces) {
						for (Class<?> ifc : clazz.getInterfaces()) {
753
							T result = searchWithFindSemantics(ifc, annotationType, searchOnInterfaces,
754 755 756 757 758 759 760 761 762 763 764
								searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
								processor, visited, metaDepth);
							if (result != null) {
								return result;
							}
						}
					}

					// Search on superclass
					if (searchOnSuperclasses) {
						Class<?> superclass = clazz.getSuperclass();
765
						if (superclass != null && Object.class != superclass) {
766
							T result = searchWithFindSemantics(superclass, annotationType, searchOnInterfaces,
767 768 769 770 771
								searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
								processor, visited, metaDepth);
							if (result != null) {
								return result;
							}
772
						}
773 774 775
					}
				}
			}
776
			catch (Exception ex) {
777
				AnnotationUtils.handleIntrospectionFailure(element, ex);
778
			}
779 780 781 782
		}
		return null;
	}

783 784 785 786 787 788 789 790
	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());
791
					T result = searchWithFindSemantics(equivalentMethod, annotationType, searchOnInterfaces,
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
						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 已提交
808 809 810 811 812 813 814 815
	private static Annotation getAnnotation(AnnotatedElement element, String annotationType) {
		for (Annotation annotation : element.getAnnotations()) {
			if (annotation.annotationType().getName().equals(annotationType)) {
				return annotation;
			}
		}
		return null;
	}
816

817

818
	/**
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
	 * 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.
838
	 *
839
	 * @param <T> the type of result returned by the processor
840
	 */
841
	private static interface Processor<T> {
842 843

		/**
844 845 846 847 848 849 850 851 852
		 * 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.
853
		 *
854
		 * <p>The {@code metaDepth} parameter represents the depth of the
855 856 857 858 859
		 * 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.
860
		 *
861 862 863
		 * @param annotatedElement the element that is annotated with the
		 * supplied annotation, used for contextual logging; may be
		 * {@code null} if unknown
864
		 * @param annotation the annotation to process
865
		 * @param metaDepth the meta-depth of the annotation
866
		 * @return the result of the processing, or {@code null} to continue
867
		 * searching for additional annotations
868
		 */
869
		T process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth);
870

871 872 873 874
		/**
		 * Post-process the result returned by the {@link #process} method.
		 *
		 * <p>The {@code annotation} supplied to this method is an annotation
875
		 * that is present in the annotation hierarchy, between the initial
876 877
		 * {@link AnnotatedElement} and an invocation of {@link #process}
		 * that returned a non-null value.
878
		 *
879 880 881
		 * @param annotatedElement the element that is annotated with the
		 * supplied annotation, used for contextual logging; may be
		 * {@code null} if unknown
882 883 884
		 * @param annotation the annotation to post-process
		 * @param result the result to post-process
		 */
885
		void postProcess(AnnotatedElement annotatedElement, Annotation annotation, T result);
886 887
	}

888
	/**
889 890
	 * {@link Processor} that {@linkplain #process processes} annotations
	 * but does not {@link #postProcess} results.
891 892 893 894 895 896 897 898
	 * @since 4.2
	 */
	private abstract static class SimpleAnnotationProcessor<T> implements Processor<T> {

		/**
		 * <em>No-op</em>.
		 */
		@Override
899
		public final void postProcess(AnnotatedElement annotatedElement, Annotation annotation, T result) {
900 901 902 903
			/* no-op */
		}
	}

904 905 906 907 908 909 910 911
	/**
	 * {@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
	 */
912
	private static class MergedAnnotationAttributesProcessor implements Processor<AnnotationAttributes> {
913

914
		private final String annotationTypeName;
915 916 917 918
		private final boolean classValuesAsString;
		private final boolean nestedAnnotationsAsMap;


919 920 921
		MergedAnnotationAttributesProcessor(String annotationType, boolean classValuesAsString,
				boolean nestedAnnotationsAsMap) {
			this.annotationTypeName = annotationType;
922 923 924 925 926
			this.classValuesAsString = classValuesAsString;
			this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
		}

		@Override
927 928 929
		public AnnotationAttributes process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
			boolean found = annotation.annotationType().getName().equals(this.annotationTypeName);
			return (found ? AnnotationUtils.getAnnotationAttributes(annotatedElement, annotation,
930
				this.classValuesAsString, this.nestedAnnotationsAsMap, true) : null);
931 932 933
		}

		@Override
934
		public void postProcess(AnnotatedElement element, Annotation annotation, AnnotationAttributes attributes) {
935
			annotation = AnnotationUtils.synthesizeAnnotation(annotation, element);
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
			Class<? extends Annotation> targetAnnotationType = attributes.annotationType();

			for (Method attributeMethod : AnnotationUtils.getAttributeMethods(annotation.annotationType())) {
				String attributeName = attributeMethod.getName();
				String aliasedAttributeName = AnnotationUtils.getAliasedAttributeName(attributeMethod,
					targetAnnotationType);

				// Explicit annotation attribute override declared via @AliasFor
				if (StringUtils.hasText(aliasedAttributeName)) {
					if (attributes.containsKey(aliasedAttributeName)) {
						Object value = AnnotationUtils.getValue(annotation, attributeName);
						attributes.put(aliasedAttributeName, AnnotationUtils.adaptValue(element, value,
							this.classValuesAsString, this.nestedAnnotationsAsMap));
					}
				}
				// Implicit annotation attribute override based on convention
				else if (!AnnotationUtils.VALUE.equals(attributeName) && attributes.containsKey(attributeName)) {
					Object value = AnnotationUtils.getValue(annotation, attributeName);
					Object adaptedValue = AnnotationUtils.adaptValue(element, value, this.classValuesAsString,
						this.nestedAnnotationsAsMap);
					attributes.put(attributeName, adaptedValue);

					// If an aliased attribute defined by @AliasFor semantics does not
					// already have an explicit value, ensure that the aliased attribute
					// is also present in the map with a value identical to its mirror
					// alias.
					Method attributeMethodInTarget = ReflectionUtils.findMethod(targetAnnotationType, attributeName);
					if (attributeMethodInTarget != null) {
						String aliasedAttributeNameInTarget = AnnotationUtils.getAliasedAttributeName(
							attributeMethodInTarget, null);
						if (aliasedAttributeNameInTarget != null) {
967
							attributes.putIfAbsent(aliasedAttributeNameInTarget, adaptedValue);
968
						}
969 970 971 972 973 974
					}
				}
			}
		}
	}

975
}