001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.annotation;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.AnnotatedElement;
021import java.lang.reflect.Array;
022import java.lang.reflect.InvocationTargetException;
023import java.lang.reflect.Method;
024import java.lang.reflect.Modifier;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.LinkedHashMap;
028import java.util.List;
029import java.util.Map;
030import java.util.NoSuchElementException;
031import java.util.Set;
032
033import org.springframework.core.BridgeMethodResolver;
034import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets.MirrorSet;
035import org.springframework.core.annotation.MergedAnnotation.Adapt;
036import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
037import org.springframework.lang.Nullable;
038import org.springframework.util.ConcurrentReferenceHashMap;
039import org.springframework.util.ReflectionUtils;
040import org.springframework.util.StringUtils;
041
042/**
043 * General utility methods for working with annotations, handling meta-annotations,
044 * bridge methods (which the compiler generates for generic declarations) as well
045 * as super methods (for optional <em>annotation inheritance</em>).
046 *
047 * <p>Note that most of the features of this class are not provided by the
048 * JDK's introspection facilities themselves.
049 *
050 * <p>As a general rule for runtime-retained application annotations (e.g. for
051 * transaction control, authorization, or service exposure), always use the
052 * lookup methods on this class (e.g. {@link #findAnnotation(Method, Class)} or
053 * {@link #getAnnotation(Method, Class)}) instead of the plain annotation lookup
054 * methods in the JDK. You can still explicitly choose between a <em>get</em>
055 * lookup on the given class level only ({@link #getAnnotation(Method, Class)})
056 * and a <em>find</em> lookup in the entire inheritance hierarchy of the given
057 * method ({@link #findAnnotation(Method, Class)}).
058 *
059 * <h3>Terminology</h3>
060 * The terms <em>directly present</em>, <em>indirectly present</em>, and
061 * <em>present</em> have the same meanings as defined in the class-level
062 * javadoc for {@link AnnotatedElement} (in Java 8).
063 *
064 * <p>An annotation is <em>meta-present</em> on an element if the annotation
065 * is declared as a meta-annotation on some other annotation which is
066 * <em>present</em> on the element. Annotation {@code A} is <em>meta-present</em>
067 * on another annotation if {@code A} is either <em>directly present</em> or
068 * <em>meta-present</em> on the other annotation.
069 *
070 * <h3>Meta-annotation Support</h3>
071 * <p>Most {@code find*()} methods and some {@code get*()} methods in this class
072 * provide support for finding annotations used as meta-annotations. Consult the
073 * javadoc for each method in this class for details. For fine-grained support for
074 * meta-annotations with <em>attribute overrides</em> in <em>composed annotations</em>,
075 * consider using {@link AnnotatedElementUtils}'s more specific methods instead.
076 *
077 * <h3>Attribute Aliases</h3>
078 * <p>All public methods in this class that return annotations, arrays of
079 * annotations, or {@link AnnotationAttributes} transparently support attribute
080 * aliases configured via {@link AliasFor @AliasFor}. Consult the various
081 * {@code synthesizeAnnotation*(..)} methods for details.
082 *
083 * <h3>Search Scope</h3>
084 * <p>The search algorithms used by methods in this class stop searching for
085 * an annotation once the first annotation of the specified type has been
086 * found. As a consequence, additional annotations of the specified type will
087 * be silently ignored.
088 *
089 * @author Rob Harrop
090 * @author Juergen Hoeller
091 * @author Sam Brannen
092 * @author Mark Fisher
093 * @author Chris Beams
094 * @author Phillip Webb
095 * @author Oleg Zhurakousky
096 * @since 2.0
097 * @see AliasFor
098 * @see AnnotationAttributes
099 * @see AnnotatedElementUtils
100 * @see BridgeMethodResolver
101 * @see java.lang.reflect.AnnotatedElement#getAnnotations()
102 * @see java.lang.reflect.AnnotatedElement#getAnnotation(Class)
103 * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotations()
104 */
105public abstract class AnnotationUtils {
106
107        /**
108         * The attribute name for annotations with a single element.
109         */
110        public static final String VALUE = MergedAnnotation.VALUE;
111
112        private static final AnnotationFilter JAVA_LANG_ANNOTATION_FILTER =
113                        AnnotationFilter.packages("java.lang.annotation");
114
115        private static final Map<Class<? extends Annotation>, Map<String, DefaultValueHolder>> defaultValuesCache =
116                        new ConcurrentReferenceHashMap<>();
117
118
119        /**
120         * Determine whether the given class is a candidate for carrying one of the specified
121         * annotations (at type, method or field level).
122         * @param clazz the class to introspect
123         * @param annotationTypes the searchable annotation types
124         * @return {@code false} if the class is known to have no such annotations at any level;
125         * {@code true} otherwise. Callers will usually perform full method/field introspection
126         * if {@code true} is being returned here.
127         * @since 5.2
128         * @see #isCandidateClass(Class, Class)
129         * @see #isCandidateClass(Class, String)
130         */
131        public static boolean isCandidateClass(Class<?> clazz, Collection<Class<? extends Annotation>> annotationTypes) {
132                for (Class<? extends Annotation> annotationType : annotationTypes) {
133                        if (isCandidateClass(clazz, annotationType)) {
134                                return true;
135                        }
136                }
137                return false;
138        }
139
140        /**
141         * Determine whether the given class is a candidate for carrying the specified annotation
142         * (at type, method or field level).
143         * @param clazz the class to introspect
144         * @param annotationType the searchable annotation type
145         * @return {@code false} if the class is known to have no such annotations at any level;
146         * {@code true} otherwise. Callers will usually perform full method/field introspection
147         * if {@code true} is being returned here.
148         * @since 5.2
149         * @see #isCandidateClass(Class, String)
150         */
151        public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
152                return isCandidateClass(clazz, annotationType.getName());
153        }
154
155        /**
156         * Determine whether the given class is a candidate for carrying the specified annotation
157         * (at type, method or field level).
158         * @param clazz the class to introspect
159         * @param annotationName the fully-qualified name of the searchable annotation type
160         * @return {@code false} if the class is known to have no such annotations at any level;
161         * {@code true} otherwise. Callers will usually perform full method/field introspection
162         * if {@code true} is being returned here.
163         * @since 5.2
164         * @see #isCandidateClass(Class, Class)
165         */
166        public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
167                if (annotationName.startsWith("java.")) {
168                        return true;
169                }
170                if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
171                        return false;
172                }
173                return true;
174        }
175
176        /**
177         * Get a single {@link Annotation} of {@code annotationType} from the supplied
178         * annotation: either the given annotation itself or a direct meta-annotation
179         * thereof.
180         * <p>Note that this method supports only a single level of meta-annotations.
181         * For support for arbitrary levels of meta-annotations, use one of the
182         * {@code find*()} methods instead.
183         * @param annotation the Annotation to check
184         * @param annotationType the annotation type to look for, both locally and as a meta-annotation
185         * @return the first matching annotation, or {@code null} if not found
186         * @since 4.0
187         */
188        @SuppressWarnings("unchecked")
189        @Nullable
190        public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType) {
191                // Shortcut: directly present on the element, with no merging needed?
192                if (annotationType.isInstance(annotation)) {
193                        return synthesizeAnnotation((A) annotation, annotationType);
194                }
195                // Shortcut: no searchable annotations to be found on plain Java classes and core Spring types...
196                if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotation)) {
197                        return null;
198                }
199                // Exhaustive retrieval of merged annotations...
200                return MergedAnnotations.from(annotation, new Annotation[] {annotation}, RepeatableContainers.none())
201                                .get(annotationType).withNonMergedAttributes()
202                                .synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null);
203        }
204
205        /**
206         * Get a single {@link Annotation} of {@code annotationType} from the supplied
207         * {@link AnnotatedElement}, where the annotation is either <em>present</em> or
208         * <em>meta-present</em> on the {@code AnnotatedElement}.
209         * <p>Note that this method supports only a single level of meta-annotations.
210         * For support for arbitrary levels of meta-annotations, use
211         * {@link #findAnnotation(AnnotatedElement, Class)} instead.
212         * @param annotatedElement the {@code AnnotatedElement} from which to get the annotation
213         * @param annotationType the annotation type to look for, both locally and as a meta-annotation
214         * @return the first matching annotation, or {@code null} if not found
215         * @since 3.1
216         */
217        @Nullable
218        public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
219                // Shortcut: directly present on the element, with no merging needed?
220                if (AnnotationFilter.PLAIN.matches(annotationType) ||
221                                AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement)) {
222                        return annotatedElement.getAnnotation(annotationType);
223                }
224                // Exhaustive retrieval of merged annotations...
225                return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none())
226                                .get(annotationType).withNonMergedAttributes()
227                                .synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null);
228        }
229
230        private static <A extends Annotation> boolean isSingleLevelPresent(MergedAnnotation<A> mergedAnnotation) {
231                int distance = mergedAnnotation.getDistance();
232                return (distance == 0 || distance == 1);
233        }
234
235        /**
236         * Get a single {@link Annotation} of {@code annotationType} from the
237         * supplied {@link Method}, where the annotation is either <em>present</em>
238         * or <em>meta-present</em> on the method.
239         * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
240         * <p>Note that this method supports only a single level of meta-annotations.
241         * For support for arbitrary levels of meta-annotations, use
242         * {@link #findAnnotation(Method, Class)} instead.
243         * @param method the method to look for annotations on
244         * @param annotationType the annotation type to look for
245         * @return the first matching annotation, or {@code null} if not found
246         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
247         * @see #getAnnotation(AnnotatedElement, Class)
248         */
249        @Nullable
250        public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
251                Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
252                return getAnnotation((AnnotatedElement) resolvedMethod, annotationType);
253        }
254
255        /**
256         * Get all {@link Annotation Annotations} that are <em>present</em> on the
257         * supplied {@link AnnotatedElement}.
258         * <p>Meta-annotations will <em>not</em> be searched.
259         * @param annotatedElement the Method, Constructor or Field to retrieve annotations from
260         * @return the annotations found, an empty array, or {@code null} if not
261         * resolvable (e.g. because nested Class values in annotation attributes
262         * failed to resolve at runtime)
263         * @since 4.0.8
264         * @see AnnotatedElement#getAnnotations()
265         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
266         */
267        @Deprecated
268        @Nullable
269        public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
270                try {
271                        return synthesizeAnnotationArray(annotatedElement.getAnnotations(), annotatedElement);
272                }
273                catch (Throwable ex) {
274                        handleIntrospectionFailure(annotatedElement, ex);
275                        return null;
276                }
277        }
278
279        /**
280         * Get all {@link Annotation Annotations} that are <em>present</em> on the
281         * supplied {@link Method}.
282         * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
283         * <p>Meta-annotations will <em>not</em> be searched.
284         * @param method the Method to retrieve annotations from
285         * @return the annotations found, an empty array, or {@code null} if not
286         * resolvable (e.g. because nested Class values in annotation attributes
287         * failed to resolve at runtime)
288         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
289         * @see AnnotatedElement#getAnnotations()
290         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
291         */
292        @Deprecated
293        @Nullable
294        public static Annotation[] getAnnotations(Method method) {
295                try {
296                        return synthesizeAnnotationArray(BridgeMethodResolver.findBridgedMethod(method).getAnnotations(), method);
297                }
298                catch (Throwable ex) {
299                        handleIntrospectionFailure(method, ex);
300                        return null;
301                }
302        }
303
304        /**
305         * Get the <em>repeatable</em> {@linkplain Annotation annotations} of
306         * {@code annotationType} from the supplied {@link AnnotatedElement}, where
307         * such annotations are either <em>present</em>, <em>indirectly present</em>,
308         * or <em>meta-present</em> on the element.
309         * <p>This method mimics the functionality of Java 8's
310         * {@link java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)}
311         * with support for automatic detection of a <em>container annotation</em>
312         * declared via @{@link java.lang.annotation.Repeatable} (when running on
313         * Java 8 or higher) and with additional support for meta-annotations.
314         * <p>Handles both single annotations and annotations nested within a
315         * <em>container annotation</em>.
316         * <p>Correctly handles <em>bridge methods</em> generated by the
317         * compiler if the supplied element is a {@link Method}.
318         * <p>Meta-annotations will be searched if the annotation is not
319         * <em>present</em> on the supplied element.
320         * @param annotatedElement the element to look for annotations on
321         * @param annotationType the annotation type to look for
322         * @return the annotations found or an empty set (never {@code null})
323         * @since 4.2
324         * @see #getRepeatableAnnotations(AnnotatedElement, Class, Class)
325         * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class, Class)
326         * @see AnnotatedElementUtils#getMergedRepeatableAnnotations(AnnotatedElement, Class)
327         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
328         * @see java.lang.annotation.Repeatable
329         * @see java.lang.reflect.AnnotatedElement#getAnnotationsByType
330         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
331         */
332        @Deprecated
333        public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
334                        Class<A> annotationType) {
335
336                return getRepeatableAnnotations(annotatedElement, annotationType, null);
337        }
338
339        /**
340         * Get the <em>repeatable</em> {@linkplain Annotation annotations} of
341         * {@code annotationType} from the supplied {@link AnnotatedElement}, where
342         * such annotations are either <em>present</em>, <em>indirectly present</em>,
343         * or <em>meta-present</em> on the element.
344         * <p>This method mimics the functionality of Java 8's
345         * {@link java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)}
346         * with additional support for meta-annotations.
347         * <p>Handles both single annotations and annotations nested within a
348         * <em>container annotation</em>.
349         * <p>Correctly handles <em>bridge methods</em> generated by the
350         * compiler if the supplied element is a {@link Method}.
351         * <p>Meta-annotations will be searched if the annotation is not
352         * <em>present</em> on the supplied element.
353         * @param annotatedElement the element to look for annotations on
354         * @param annotationType the annotation type to look for
355         * @param containerAnnotationType the type of the container that holds
356         * the annotations; may be {@code null} if a container is not supported
357         * or if it should be looked up via @{@link java.lang.annotation.Repeatable}
358         * when running on Java 8 or higher
359         * @return the annotations found or an empty set (never {@code null})
360         * @since 4.2
361         * @see #getRepeatableAnnotations(AnnotatedElement, Class)
362         * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class)
363         * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class, Class)
364         * @see AnnotatedElementUtils#getMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
365         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
366         * @see java.lang.annotation.Repeatable
367         * @see java.lang.reflect.AnnotatedElement#getAnnotationsByType
368         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
369         */
370        @Deprecated
371        public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
372                        Class<A> annotationType, @Nullable Class<? extends Annotation> containerAnnotationType) {
373
374                RepeatableContainers repeatableContainers = (containerAnnotationType != null ?
375                                RepeatableContainers.of(annotationType, containerAnnotationType) :
376                                RepeatableContainers.standardRepeatables());
377
378                return MergedAnnotations.from(annotatedElement, SearchStrategy.SUPERCLASS, repeatableContainers)
379                                .stream(annotationType)
380                                .filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex))
381                                .map(MergedAnnotation::withNonMergedAttributes)
382                                .collect(MergedAnnotationCollectors.toAnnotationSet());
383        }
384
385        /**
386         * Get the declared <em>repeatable</em> {@linkplain Annotation annotations}
387         * of {@code annotationType} from the supplied {@link AnnotatedElement},
388         * where such annotations are either <em>directly present</em>,
389         * <em>indirectly present</em>, or <em>meta-present</em> on the element.
390         * <p>This method mimics the functionality of Java 8's
391         * {@link java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType(Class)}
392         * with support for automatic detection of a <em>container annotation</em>
393         * declared via @{@link java.lang.annotation.Repeatable} (when running on
394         * Java 8 or higher) and with additional support for meta-annotations.
395         * <p>Handles both single annotations and annotations nested within a
396         * <em>container annotation</em>.
397         * <p>Correctly handles <em>bridge methods</em> generated by the
398         * compiler if the supplied element is a {@link Method}.
399         * <p>Meta-annotations will be searched if the annotation is not
400         * <em>present</em> on the supplied element.
401         * @param annotatedElement the element to look for annotations on
402         * @param annotationType the annotation type to look for
403         * @return the annotations found or an empty set (never {@code null})
404         * @since 4.2
405         * @see #getRepeatableAnnotations(AnnotatedElement, Class)
406         * @see #getRepeatableAnnotations(AnnotatedElement, Class, Class)
407         * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class, Class)
408         * @see AnnotatedElementUtils#getMergedRepeatableAnnotations(AnnotatedElement, Class)
409         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
410         * @see java.lang.annotation.Repeatable
411         * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType
412         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
413         */
414        @Deprecated
415        public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(AnnotatedElement annotatedElement,
416                        Class<A> annotationType) {
417
418                return getDeclaredRepeatableAnnotations(annotatedElement, annotationType, null);
419        }
420
421        /**
422         * Get the declared <em>repeatable</em> {@linkplain Annotation annotations}
423         * of {@code annotationType} from the supplied {@link AnnotatedElement},
424         * where such annotations are either <em>directly present</em>,
425         * <em>indirectly present</em>, or <em>meta-present</em> on the element.
426         * <p>This method mimics the functionality of Java 8's
427         * {@link java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType(Class)}
428         * with additional support for meta-annotations.
429         * <p>Handles both single annotations and annotations nested within a
430         * <em>container annotation</em>.
431         * <p>Correctly handles <em>bridge methods</em> generated by the
432         * compiler if the supplied element is a {@link Method}.
433         * <p>Meta-annotations will be searched if the annotation is not
434         * <em>present</em> on the supplied element.
435         * @param annotatedElement the element to look for annotations on
436         * @param annotationType the annotation type to look for
437         * @param containerAnnotationType the type of the container that holds
438         * the annotations; may be {@code null} if a container is not supported
439         * or if it should be looked up via @{@link java.lang.annotation.Repeatable}
440         * when running on Java 8 or higher
441         * @return the annotations found or an empty set (never {@code null})
442         * @since 4.2
443         * @see #getRepeatableAnnotations(AnnotatedElement, Class)
444         * @see #getRepeatableAnnotations(AnnotatedElement, Class, Class)
445         * @see #getDeclaredRepeatableAnnotations(AnnotatedElement, Class)
446         * @see AnnotatedElementUtils#getMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
447         * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod
448         * @see java.lang.annotation.Repeatable
449         * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType
450         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
451         */
452        @Deprecated
453        public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(AnnotatedElement annotatedElement,
454                        Class<A> annotationType, @Nullable Class<? extends Annotation> containerAnnotationType) {
455
456                RepeatableContainers repeatableContainers = containerAnnotationType != null ?
457                                RepeatableContainers.of(annotationType, containerAnnotationType) :
458                                RepeatableContainers.standardRepeatables();
459
460                return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT, repeatableContainers)
461                                .stream(annotationType)
462                                .map(MergedAnnotation::withNonMergedAttributes)
463                                .collect(MergedAnnotationCollectors.toAnnotationSet());
464        }
465
466        /**
467         * Find a single {@link Annotation} of {@code annotationType} on the
468         * supplied {@link AnnotatedElement}.
469         * <p>Meta-annotations will be searched if the annotation is not
470         * <em>directly present</em> on the supplied element.
471         * <p><strong>Warning</strong>: this method operates generically on
472         * annotated elements. In other words, this method does not execute
473         * specialized search algorithms for classes or methods. If you require
474         * the more specific semantics of {@link #findAnnotation(Class, Class)}
475         * or {@link #findAnnotation(Method, Class)}, invoke one of those methods
476         * instead.
477         * @param annotatedElement the {@code AnnotatedElement} on which to find the annotation
478         * @param annotationType the annotation type to look for, both locally and as a meta-annotation
479         * @return the first matching annotation, or {@code null} if not found
480         * @since 4.2
481         */
482        @Nullable
483        public static <A extends Annotation> A findAnnotation(
484                        AnnotatedElement annotatedElement, @Nullable Class<A> annotationType) {
485
486                if (annotationType == null) {
487                        return null;
488                }
489
490                // Shortcut: directly present on the element, with no merging needed?
491                if (AnnotationFilter.PLAIN.matches(annotationType) ||
492                                AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement)) {
493                        return annotatedElement.getDeclaredAnnotation(annotationType);
494                }
495
496                // Exhaustive retrieval of merged annotations...
497                return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none())
498                                .get(annotationType).withNonMergedAttributes()
499                                .synthesize(MergedAnnotation::isPresent).orElse(null);
500        }
501
502        /**
503         * Find a single {@link Annotation} of {@code annotationType} on the supplied
504         * {@link Method}, traversing its super methods (i.e. from superclasses and
505         * interfaces) if the annotation is not <em>directly present</em> on the given
506         * method itself.
507         * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
508         * <p>Meta-annotations will be searched if the annotation is not
509         * <em>directly present</em> on the method.
510         * <p>Annotations on methods are not inherited by default, so we need to handle
511         * this explicitly.
512         * @param method the method to look for annotations on
513         * @param annotationType the annotation type to look for
514         * @return the first matching annotation, or {@code null} if not found
515         * @see #getAnnotation(Method, Class)
516         */
517        @Nullable
518        public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType) {
519                if (annotationType == null) {
520                        return null;
521                }
522
523                // Shortcut: directly present on the element, with no merging needed?
524                if (AnnotationFilter.PLAIN.matches(annotationType) ||
525                                AnnotationsScanner.hasPlainJavaAnnotationsOnly(method)) {
526                        return method.getDeclaredAnnotation(annotationType);
527                }
528
529                // Exhaustive retrieval of merged annotations...
530                return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
531                                .get(annotationType).withNonMergedAttributes()
532                                .synthesize(MergedAnnotation::isPresent).orElse(null);
533        }
534
535        /**
536         * Find a single {@link Annotation} of {@code annotationType} on the
537         * supplied {@link Class}, traversing its interfaces, annotations, and
538         * superclasses if the annotation is not <em>directly present</em> on
539         * the given class itself.
540         * <p>This method explicitly handles class-level annotations which are not
541         * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
542         * as meta-annotations and annotations on interfaces</em>.
543         * <p>The algorithm operates as follows:
544         * <ol>
545         * <li>Search for the annotation on the given class and return it if found.
546         * <li>Recursively search through all annotations that the given class declares.
547         * <li>Recursively search through all interfaces that the given class declares.
548         * <li>Recursively search through the superclass hierarchy of the given class.
549         * </ol>
550         * <p>Note: in this context, the term <em>recursively</em> means that the search
551         * process continues by returning to step #1 with the current interface,
552         * annotation, or superclass as the class to look for annotations on.
553         * @param clazz the class to look for annotations on
554         * @param annotationType the type of annotation to look for
555         * @return the first matching annotation, or {@code null} if not found
556         */
557        @Nullable
558        public static <A extends Annotation> A findAnnotation(Class<?> clazz, @Nullable Class<A> annotationType) {
559                if (annotationType == null) {
560                        return null;
561                }
562
563                // Shortcut: directly present on the element, with no merging needed?
564                if (AnnotationFilter.PLAIN.matches(annotationType) ||
565                                AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
566                        A annotation = clazz.getDeclaredAnnotation(annotationType);
567                        if (annotation != null) {
568                                return annotation;
569                        }
570                        // For backwards compatibility, perform a superclass search with plain annotations
571                        // even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
572                        Class<?> superclass = clazz.getSuperclass();
573                        if (superclass == null || superclass == Object.class) {
574                                return null;
575                        }
576                        return findAnnotation(superclass, annotationType);
577                }
578
579                // Exhaustive retrieval of merged annotations...
580                return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
581                                .get(annotationType).withNonMergedAttributes()
582                                .synthesize(MergedAnnotation::isPresent).orElse(null);
583        }
584
585        /**
586         * Find the first {@link Class} in the inheritance hierarchy of the
587         * specified {@code clazz} (including the specified {@code clazz} itself)
588         * on which an annotation of the specified {@code annotationType} is
589         * <em>directly present</em>.
590         * <p>If the supplied {@code clazz} is an interface, only the interface
591         * itself will be checked; the inheritance hierarchy for interfaces will
592         * not be traversed.
593         * <p>Meta-annotations will <em>not</em> be searched.
594         * <p>The standard {@link Class} API does not provide a mechanism for
595         * determining which class in an inheritance hierarchy actually declares
596         * an {@link Annotation}, so we need to handle this explicitly.
597         * @param annotationType the annotation type to look for
598         * @param clazz the class to check for the annotation on (may be {@code null})
599         * @return the first {@link Class} in the inheritance hierarchy that
600         * declares an annotation of the specified {@code annotationType},
601         * or {@code null} if not found
602         * @see Class#isAnnotationPresent(Class)
603         * @see Class#getDeclaredAnnotations()
604         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
605         */
606        @Deprecated
607        @Nullable
608        public static Class<?> findAnnotationDeclaringClass(
609                        Class<? extends Annotation> annotationType, @Nullable Class<?> clazz) {
610
611                if (clazz == null) {
612                        return null;
613                }
614
615                return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS)
616                                .get(annotationType, MergedAnnotation::isDirectlyPresent)
617                                .getSource();
618        }
619
620        /**
621         * Find the first {@link Class} in the inheritance hierarchy of the
622         * specified {@code clazz} (including the specified {@code clazz} itself)
623         * on which at least one of the specified {@code annotationTypes} is
624         * <em>directly present</em>.
625         * <p>If the supplied {@code clazz} is an interface, only the interface
626         * itself will be checked; the inheritance hierarchy for interfaces will
627         * not be traversed.
628         * <p>Meta-annotations will <em>not</em> be searched.
629         * <p>The standard {@link Class} API does not provide a mechanism for
630         * determining which class in an inheritance hierarchy actually declares
631         * one of several candidate {@linkplain Annotation annotations}, so we
632         * need to handle this explicitly.
633         * @param annotationTypes the annotation types to look for
634         * @param clazz the class to check for the annotation on (may be {@code null})
635         * @return the first {@link Class} in the inheritance hierarchy that
636         * declares an annotation of at least one of the specified
637         * {@code annotationTypes}, or {@code null} if not found
638         * @since 3.2.2
639         * @see Class#isAnnotationPresent(Class)
640         * @see Class#getDeclaredAnnotations()
641         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
642         */
643        @Deprecated
644        @Nullable
645        public static Class<?> findAnnotationDeclaringClassForTypes(
646                        List<Class<? extends Annotation>> annotationTypes, @Nullable Class<?> clazz) {
647
648                if (clazz == null) {
649                        return null;
650                }
651
652                return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS)
653                                .stream()
654                                .filter(MergedAnnotationPredicates.typeIn(annotationTypes).and(MergedAnnotation::isDirectlyPresent))
655                                .map(MergedAnnotation::getSource)
656                                .findFirst().orElse(null);
657        }
658
659        /**
660         * Determine whether an annotation of the specified {@code annotationType}
661         * is declared locally (i.e. <em>directly present</em>) on the supplied
662         * {@code clazz}.
663         * <p>The supplied {@link Class} may represent any type.
664         * <p>Meta-annotations will <em>not</em> be searched.
665         * <p>Note: This method does <strong>not</strong> determine if the annotation
666         * is {@linkplain java.lang.annotation.Inherited inherited}.
667         * @param annotationType the annotation type to look for
668         * @param clazz the class to check for the annotation on
669         * @return {@code true} if an annotation of the specified {@code annotationType}
670         * is <em>directly present</em>
671         * @see java.lang.Class#getDeclaredAnnotations()
672         * @see java.lang.Class#getDeclaredAnnotation(Class)
673         */
674        public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
675                return MergedAnnotations.from(clazz).get(annotationType).isDirectlyPresent();
676        }
677
678        /**
679         * Determine whether an annotation of the specified {@code annotationType}
680         * is <em>present</em> on the supplied {@code clazz} and is
681         * {@linkplain java.lang.annotation.Inherited inherited}
682         * (i.e. not <em>directly present</em>).
683         * <p>Meta-annotations will <em>not</em> be searched.
684         * <p>If the supplied {@code clazz} is an interface, only the interface
685         * itself will be checked. In accordance with standard meta-annotation
686         * semantics in Java, the inheritance hierarchy for interfaces will not
687         * be traversed. See the {@linkplain java.lang.annotation.Inherited javadoc}
688         * for the {@code @Inherited} meta-annotation for further details regarding
689         * annotation inheritance.
690         * @param annotationType the annotation type to look for
691         * @param clazz the class to check for the annotation on
692         * @return {@code true} if an annotation of the specified {@code annotationType}
693         * is <em>present</em> and <em>inherited</em>
694         * @see Class#isAnnotationPresent(Class)
695         * @see #isAnnotationDeclaredLocally(Class, Class)
696         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
697         */
698        @Deprecated
699        public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz) {
700                return MergedAnnotations.from(clazz, SearchStrategy.INHERITED_ANNOTATIONS)
701                                .stream(annotationType)
702                                .filter(MergedAnnotation::isDirectlyPresent)
703                                .findFirst().orElseGet(MergedAnnotation::missing)
704                                .getAggregateIndex() > 0;
705        }
706
707        /**
708         * Determine if an annotation of type {@code metaAnnotationType} is
709         * <em>meta-present</em> on the supplied {@code annotationType}.
710         * @param annotationType the annotation type to search on
711         * @param metaAnnotationType the type of meta-annotation to search for
712         * @return {@code true} if such an annotation is meta-present
713         * @since 4.2.1
714         * @deprecated as of 5.2 since it is superseded by the {@link MergedAnnotations} API
715         */
716        @Deprecated
717        public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType,
718                        @Nullable Class<? extends Annotation> metaAnnotationType) {
719
720                if (metaAnnotationType == null) {
721                        return false;
722                }
723                // Shortcut: directly present on the element, with no merging needed?
724                if (AnnotationFilter.PLAIN.matches(metaAnnotationType) ||
725                                AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotationType)) {
726                        return annotationType.isAnnotationPresent(metaAnnotationType);
727                }
728                // Exhaustive retrieval of merged annotations...
729                return MergedAnnotations.from(annotationType, SearchStrategy.INHERITED_ANNOTATIONS,
730                                RepeatableContainers.none()).isPresent(metaAnnotationType);
731        }
732
733        /**
734         * Determine if the supplied {@link Annotation} is defined in the core JDK
735         * {@code java.lang.annotation} package.
736         * @param annotation the annotation to check
737         * @return {@code true} if the annotation is in the {@code java.lang.annotation} package
738         */
739        public static boolean isInJavaLangAnnotationPackage(@Nullable Annotation annotation) {
740                return (annotation != null && JAVA_LANG_ANNOTATION_FILTER.matches(annotation));
741        }
742
743        /**
744         * Determine if the {@link Annotation} with the supplied name is defined
745         * in the core JDK {@code java.lang.annotation} package.
746         * @param annotationType the name of the annotation type to check
747         * @return {@code true} if the annotation is in the {@code java.lang.annotation} package
748         * @since 4.2
749         */
750        public static boolean isInJavaLangAnnotationPackage(@Nullable String annotationType) {
751                return (annotationType != null && JAVA_LANG_ANNOTATION_FILTER.matches(annotationType));
752        }
753
754        /**
755         * Check the declared attributes of the given annotation, in particular covering
756         * Google App Engine's late arrival of {@code TypeNotPresentExceptionProxy} for
757         * {@code Class} values (instead of early {@code Class.getAnnotations() failure}.
758         * <p>This method not failing indicates that {@link #getAnnotationAttributes(Annotation)}
759         * won't failure either (when attempted later on).
760         * @param annotation the annotation to validate
761         * @throws IllegalStateException if a declared {@code Class} attribute could not be read
762         * @since 4.3.15
763         * @see Class#getAnnotations()
764         * @see #getAnnotationAttributes(Annotation)
765         */
766        public static void validateAnnotation(Annotation annotation) {
767                AttributeMethods.forAnnotationType(annotation.annotationType()).validate(annotation);
768        }
769
770        /**
771         * Retrieve the given annotation's attributes as a {@link Map}, preserving all
772         * attribute types.
773         * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)}
774         * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters
775         * set to {@code false}.
776         * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
777         * However, the {@code Map} signature has been preserved for binary compatibility.
778         * @param annotation the annotation to retrieve the attributes for
779         * @return the Map of annotation attributes, with attribute names as keys and
780         * corresponding attribute values as values (never {@code null})
781         * @see #getAnnotationAttributes(AnnotatedElement, Annotation)
782         * @see #getAnnotationAttributes(Annotation, boolean, boolean)
783         * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
784         */
785        public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
786                return getAnnotationAttributes(null, annotation);
787        }
788
789        /**
790         * Retrieve the given annotation's attributes as a {@link Map}.
791         * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)}
792         * with the {@code nestedAnnotationsAsMap} parameter set to {@code false}.
793         * <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
794         * However, the {@code Map} signature has been preserved for binary compatibility.
795         * @param annotation the annotation to retrieve the attributes for
796         * @param classValuesAsString whether to convert Class references into Strings (for
797         * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
798         * or to preserve them as Class references
799         * @return the Map of annotation attributes, with attribute names as keys and
800         * corresponding attribute values as values (never {@code null})
801         * @see #getAnnotationAttributes(Annotation, boolean, boolean)
802         */
803        public static Map<String, Object> getAnnotationAttributes(
804                        Annotation annotation, boolean classValuesAsString) {
805
806                return getAnnotationAttributes(annotation, classValuesAsString, false);
807        }
808
809        /**
810         * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
811         * <p>This method provides fully recursive annotation reading capabilities on par with
812         * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
813         * @param annotation the annotation to retrieve the attributes for
814         * @param classValuesAsString whether to convert Class references into Strings (for
815         * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
816         * or to preserve them as Class references
817         * @param nestedAnnotationsAsMap whether to convert nested annotations into
818         * {@link AnnotationAttributes} maps (for compatibility with
819         * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
820         * {@code Annotation} instances
821         * @return the annotation attributes (a specialized Map) with attribute names as keys
822         * and corresponding attribute values as values (never {@code null})
823         * @since 3.1.1
824         */
825        public static AnnotationAttributes getAnnotationAttributes(
826                        Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
827
828                return getAnnotationAttributes(null, annotation, classValuesAsString, nestedAnnotationsAsMap);
829        }
830
831        /**
832         * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
833         * <p>Equivalent to calling {@link #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)}
834         * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters
835         * set to {@code false}.
836         * @param annotatedElement the element that is annotated with the supplied annotation;
837         * may be {@code null} if unknown
838         * @param annotation the annotation to retrieve the attributes for
839         * @return the annotation attributes (a specialized Map) with attribute names as keys
840         * and corresponding attribute values as values (never {@code null})
841         * @since 4.2
842         * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
843         */
844        public static AnnotationAttributes getAnnotationAttributes(
845                        @Nullable AnnotatedElement annotatedElement, Annotation annotation) {
846
847                return getAnnotationAttributes(annotatedElement, annotation, false, false);
848        }
849
850        /**
851         * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map.
852         * <p>This method provides fully recursive annotation reading capabilities on par with
853         * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
854         * @param annotatedElement the element that is annotated with the supplied annotation;
855         * may be {@code null} if unknown
856         * @param annotation the annotation to retrieve the attributes for
857         * @param classValuesAsString whether to convert Class references into Strings (for
858         * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
859         * or to preserve them as Class references
860         * @param nestedAnnotationsAsMap whether to convert nested annotations into
861         * {@link AnnotationAttributes} maps (for compatibility with
862         * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
863         * {@code Annotation} instances
864         * @return the annotation attributes (a specialized Map) with attribute names as keys
865         * and corresponding attribute values as values (never {@code null})
866         * @since 4.2
867         */
868        public static AnnotationAttributes getAnnotationAttributes(
869                        @Nullable AnnotatedElement annotatedElement, Annotation annotation,
870                        boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
871
872                Adapt[] adaptations = Adapt.values(classValuesAsString, nestedAnnotationsAsMap);
873                return MergedAnnotation.from(annotatedElement, annotation)
874                                .withNonMergedAttributes()
875                                .asMap(mergedAnnotation ->
876                                                new AnnotationAttributes(mergedAnnotation.getType(), true), adaptations);
877        }
878
879        /**
880         * Register the annotation-declared default values for the given attributes,
881         * if available.
882         * @param attributes the annotation attributes to process
883         * @since 4.3.2
884         */
885        public static void registerDefaultValues(AnnotationAttributes attributes) {
886                Class<? extends Annotation> annotationType = attributes.annotationType();
887                if (annotationType != null && Modifier.isPublic(annotationType.getModifiers()) &&
888                                !AnnotationFilter.PLAIN.matches(annotationType)) {
889                        Map<String, DefaultValueHolder> defaultValues = getDefaultValues(annotationType);
890                        defaultValues.forEach(attributes::putIfAbsent);
891                }
892        }
893
894        private static Map<String, DefaultValueHolder> getDefaultValues(
895                        Class<? extends Annotation> annotationType) {
896
897                return defaultValuesCache.computeIfAbsent(annotationType,
898                                AnnotationUtils::computeDefaultValues);
899        }
900
901        private static Map<String, DefaultValueHolder> computeDefaultValues(
902                        Class<? extends Annotation> annotationType) {
903
904                AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType);
905                if (!methods.hasDefaultValueMethod()) {
906                        return Collections.emptyMap();
907                }
908                Map<String, DefaultValueHolder> result = new LinkedHashMap<>(methods.size());
909                if (!methods.hasNestedAnnotation()) {
910                        // Use simpler method if there are no nested annotations
911                        for (int i = 0; i < methods.size(); i++) {
912                                Method method = methods.get(i);
913                                Object defaultValue = method.getDefaultValue();
914                                if (defaultValue != null) {
915                                        result.put(method.getName(), new DefaultValueHolder(defaultValue));
916                                }
917                        }
918                }
919                else {
920                        // If we have nested annotations, we need them as nested maps
921                        AnnotationAttributes attributes = MergedAnnotation.of(annotationType)
922                                        .asMap(annotation ->
923                                                        new AnnotationAttributes(annotation.getType(), true), Adapt.ANNOTATION_TO_MAP);
924                        for (Map.Entry<String, Object> element : attributes.entrySet()) {
925                                result.put(element.getKey(), new DefaultValueHolder(element.getValue()));
926                        }
927                }
928                return result;
929        }
930
931        /**
932         * Post-process the supplied {@link AnnotationAttributes}, preserving nested
933         * annotations as {@code Annotation} instances.
934         * <p>Specifically, this method enforces <em>attribute alias</em> semantics
935         * for annotation attributes that are annotated with {@link AliasFor @AliasFor}
936         * and replaces default value placeholders with their original default values.
937         * @param annotatedElement the element that is annotated with an annotation or
938         * annotation hierarchy from which the supplied attributes were created;
939         * may be {@code null} if unknown
940         * @param attributes the annotation attributes to post-process
941         * @param classValuesAsString whether to convert Class references into Strings (for
942         * compatibility with {@link org.springframework.core.type.AnnotationMetadata})
943         * or to preserve them as Class references
944         * @since 4.3.2
945         * @see #getDefaultValue(Class, String)
946         */
947        public static void postProcessAnnotationAttributes(@Nullable Object annotatedElement,
948                        @Nullable AnnotationAttributes attributes, boolean classValuesAsString) {
949
950                if (attributes == null) {
951                        return;
952                }
953                if (!attributes.validated) {
954                        Class<? extends Annotation> annotationType = attributes.annotationType();
955                        if (annotationType == null) {
956                                return;
957                        }
958                        AnnotationTypeMapping mapping = AnnotationTypeMappings.forAnnotationType(annotationType).get(0);
959                        for (int i = 0; i < mapping.getMirrorSets().size(); i++) {
960                                MirrorSet mirrorSet = mapping.getMirrorSets().get(i);
961                                int resolved = mirrorSet.resolve(attributes.displayName, attributes,
962                                                AnnotationUtils::getAttributeValueForMirrorResolution);
963                                if (resolved != -1) {
964                                        Method attribute = mapping.getAttributes().get(resolved);
965                                        Object value = attributes.get(attribute.getName());
966                                        for (int j = 0; j < mirrorSet.size(); j++) {
967                                                Method mirror = mirrorSet.get(j);
968                                                if (mirror != attribute) {
969                                                        attributes.put(mirror.getName(),
970                                                                        adaptValue(annotatedElement, value, classValuesAsString));
971                                                }
972                                        }
973                                }
974                        }
975                }
976                for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) {
977                        String attributeName = attributeEntry.getKey();
978                        Object value = attributeEntry.getValue();
979                        if (value instanceof DefaultValueHolder) {
980                                value = ((DefaultValueHolder) value).defaultValue;
981                                attributes.put(attributeName,
982                                                adaptValue(annotatedElement, value, classValuesAsString));
983                        }
984                }
985        }
986
987        private static Object getAttributeValueForMirrorResolution(Method attribute, Object attributes) {
988                Object result = ((AnnotationAttributes) attributes).get(attribute.getName());
989                return (result instanceof DefaultValueHolder ? ((DefaultValueHolder) result).defaultValue : result);
990        }
991
992        @Nullable
993        private static Object adaptValue(
994                        @Nullable Object annotatedElement, @Nullable Object value, boolean classValuesAsString) {
995
996                if (classValuesAsString) {
997                        if (value instanceof Class) {
998                                return ((Class<?>) value).getName();
999                        }
1000                        if (value instanceof Class[]) {
1001                                Class<?>[] classes = (Class<?>[]) value;
1002                                String[] names = new String[classes.length];
1003                                for (int i = 0; i < classes.length; i++) {
1004                                        names[i] = classes[i].getName();
1005                                }
1006                                return names;
1007                        }
1008                }
1009                if (value instanceof Annotation) {
1010                        Annotation annotation = (Annotation) value;
1011                        return MergedAnnotation.from(annotatedElement, annotation).synthesize();
1012                }
1013                if (value instanceof Annotation[]) {
1014                        Annotation[] annotations = (Annotation[]) value;
1015                        Annotation[] synthesized = (Annotation[]) Array.newInstance(
1016                                        annotations.getClass().getComponentType(), annotations.length);
1017                        for (int i = 0; i < annotations.length; i++) {
1018                                synthesized[i] = MergedAnnotation.from(annotatedElement, annotations[i]).synthesize();
1019                        }
1020                        return synthesized;
1021                }
1022                return value;
1023        }
1024
1025        /**
1026         * Retrieve the <em>value</em> of the {@code value} attribute of a
1027         * single-element Annotation, given an annotation instance.
1028         * @param annotation the annotation instance from which to retrieve the value
1029         * @return the attribute value, or {@code null} if not found unless the attribute
1030         * value cannot be retrieved due to an {@link AnnotationConfigurationException},
1031         * in which case such an exception will be rethrown
1032         * @see #getValue(Annotation, String)
1033         */
1034        @Nullable
1035        public static Object getValue(Annotation annotation) {
1036                return getValue(annotation, VALUE);
1037        }
1038
1039        /**
1040         * Retrieve the <em>value</em> of a named attribute, given an annotation instance.
1041         * @param annotation the annotation instance from which to retrieve the value
1042         * @param attributeName the name of the attribute value to retrieve
1043         * @return the attribute value, or {@code null} if not found unless the attribute
1044         * value cannot be retrieved due to an {@link AnnotationConfigurationException},
1045         * in which case such an exception will be rethrown
1046         * @see #getValue(Annotation)
1047         */
1048        @Nullable
1049        public static Object getValue(@Nullable Annotation annotation, @Nullable String attributeName) {
1050                if (annotation == null || !StringUtils.hasText(attributeName)) {
1051                        return null;
1052                }
1053                try {
1054                        Method method = annotation.annotationType().getDeclaredMethod(attributeName);
1055                        ReflectionUtils.makeAccessible(method);
1056                        return method.invoke(annotation);
1057                }
1058                catch (NoSuchMethodException ex) {
1059                        return null;
1060                }
1061                catch (InvocationTargetException ex) {
1062                        rethrowAnnotationConfigurationException(ex.getTargetException());
1063                        throw new IllegalStateException("Could not obtain value for annotation attribute '" +
1064                                        attributeName + "' in " + annotation, ex);
1065                }
1066                catch (Throwable ex) {
1067                        handleIntrospectionFailure(annotation.getClass(), ex);
1068                        return null;
1069                }
1070        }
1071
1072        /**
1073         * If the supplied throwable is an {@link AnnotationConfigurationException},
1074         * it will be cast to an {@code AnnotationConfigurationException} and thrown,
1075         * allowing it to propagate to the caller.
1076         * <p>Otherwise, this method does nothing.
1077         * @param ex the throwable to inspect
1078         */
1079        static void rethrowAnnotationConfigurationException(Throwable ex) {
1080                if (ex instanceof AnnotationConfigurationException) {
1081                        throw (AnnotationConfigurationException) ex;
1082                }
1083        }
1084
1085        /**
1086         * Handle the supplied annotation introspection exception.
1087         * <p>If the supplied exception is an {@link AnnotationConfigurationException},
1088         * it will simply be thrown, allowing it to propagate to the caller, and
1089         * nothing will be logged.
1090         * <p>Otherwise, this method logs an introspection failure (in particular for
1091         * a {@link TypeNotPresentException}) before moving on, assuming nested
1092         * {@code Class} values were not resolvable within annotation attributes and
1093         * thereby effectively pretending there were no annotations on the specified
1094         * element.
1095         * @param element the element that we tried to introspect annotations on
1096         * @param ex the exception that we encountered
1097         * @see #rethrowAnnotationConfigurationException
1098         * @see IntrospectionFailureLogger
1099         */
1100        static void handleIntrospectionFailure(@Nullable AnnotatedElement element, Throwable ex) {
1101                rethrowAnnotationConfigurationException(ex);
1102                IntrospectionFailureLogger logger = IntrospectionFailureLogger.INFO;
1103                boolean meta = false;
1104                if (element instanceof Class && Annotation.class.isAssignableFrom((Class<?>) element)) {
1105                        // Meta-annotation or (default) value lookup on an annotation type
1106                        logger = IntrospectionFailureLogger.DEBUG;
1107                        meta = true;
1108                }
1109                if (logger.isEnabled()) {
1110                        String message = meta ?
1111                                        "Failed to meta-introspect annotation " :
1112                                        "Failed to introspect annotations on ";
1113                        logger.log(message + element + ": " + ex);
1114                }
1115        }
1116
1117        /**
1118         * Retrieve the <em>default value</em> of the {@code value} attribute
1119         * of a single-element Annotation, given an annotation instance.
1120         * @param annotation the annotation instance from which to retrieve the default value
1121         * @return the default value, or {@code null} if not found
1122         * @see #getDefaultValue(Annotation, String)
1123         */
1124        @Nullable
1125        public static Object getDefaultValue(Annotation annotation) {
1126                return getDefaultValue(annotation, VALUE);
1127        }
1128
1129        /**
1130         * Retrieve the <em>default value</em> of a named attribute, given an annotation instance.
1131         * @param annotation the annotation instance from which to retrieve the default value
1132         * @param attributeName the name of the attribute value to retrieve
1133         * @return the default value of the named attribute, or {@code null} if not found
1134         * @see #getDefaultValue(Class, String)
1135         */
1136        @Nullable
1137        public static Object getDefaultValue(@Nullable Annotation annotation, @Nullable String attributeName) {
1138                return (annotation != null ? getDefaultValue(annotation.annotationType(), attributeName) : null);
1139        }
1140
1141        /**
1142         * Retrieve the <em>default value</em> of the {@code value} attribute
1143         * of a single-element Annotation, given the {@link Class annotation type}.
1144         * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
1145         * @return the default value, or {@code null} if not found
1146         * @see #getDefaultValue(Class, String)
1147         */
1148        @Nullable
1149        public static Object getDefaultValue(Class<? extends Annotation> annotationType) {
1150                return getDefaultValue(annotationType, VALUE);
1151        }
1152
1153        /**
1154         * Retrieve the <em>default value</em> of a named attribute, given the
1155         * {@link Class annotation type}.
1156         * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
1157         * @param attributeName the name of the attribute value to retrieve.
1158         * @return the default value of the named attribute, or {@code null} if not found
1159         * @see #getDefaultValue(Annotation, String)
1160         */
1161        @Nullable
1162        public static Object getDefaultValue(
1163                        @Nullable Class<? extends Annotation> annotationType, @Nullable String attributeName) {
1164
1165                if (annotationType == null || !StringUtils.hasText(attributeName)) {
1166                        return null;
1167                }
1168                return MergedAnnotation.of(annotationType).getDefaultValue(attributeName).orElse(null);
1169        }
1170
1171        /**
1172         * <em>Synthesize</em> an annotation from the supplied {@code annotation}
1173         * by wrapping it in a dynamic proxy that transparently enforces
1174         * <em>attribute alias</em> semantics for annotation attributes that are
1175         * annotated with {@link AliasFor @AliasFor}.
1176         * @param annotation the annotation to synthesize
1177         * @param annotatedElement the element that is annotated with the supplied
1178         * annotation; may be {@code null} if unknown
1179         * @return the synthesized annotation if the supplied annotation is
1180         * <em>synthesizable</em>; {@code null} if the supplied annotation is
1181         * {@code null}; otherwise the supplied annotation unmodified
1182         * @throws AnnotationConfigurationException if invalid configuration of
1183         * {@code @AliasFor} is detected
1184         * @since 4.2
1185         * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
1186         * @see #synthesizeAnnotation(Class)
1187         */
1188        public static <A extends Annotation> A synthesizeAnnotation(
1189                        A annotation, @Nullable AnnotatedElement annotatedElement) {
1190
1191                if (annotation instanceof SynthesizedAnnotation || AnnotationFilter.PLAIN.matches(annotation)) {
1192                        return annotation;
1193                }
1194                return MergedAnnotation.from(annotatedElement, annotation).synthesize();
1195        }
1196
1197        /**
1198         * <em>Synthesize</em> an annotation from its default attributes values.
1199         * <p>This method simply delegates to
1200         * {@link #synthesizeAnnotation(Map, Class, AnnotatedElement)},
1201         * supplying an empty map for the source attribute values and {@code null}
1202         * for the {@link AnnotatedElement}.
1203         * @param annotationType the type of annotation to synthesize
1204         * @return the synthesized annotation
1205         * @throws IllegalArgumentException if a required attribute is missing
1206         * @throws AnnotationConfigurationException if invalid configuration of
1207         * {@code @AliasFor} is detected
1208         * @since 4.2
1209         * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
1210         * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
1211         */
1212        public static <A extends Annotation> A synthesizeAnnotation(Class<A> annotationType) {
1213                return synthesizeAnnotation(Collections.emptyMap(), annotationType, null);
1214        }
1215
1216        /**
1217         * <em>Synthesize</em> an annotation from the supplied map of annotation
1218         * attributes by wrapping the map in a dynamic proxy that implements an
1219         * annotation of the specified {@code annotationType} and transparently
1220         * enforces <em>attribute alias</em> semantics for annotation attributes
1221         * that are annotated with {@link AliasFor @AliasFor}.
1222         * <p>The supplied map must contain a key-value pair for every attribute
1223         * defined in the supplied {@code annotationType} that is not aliased or
1224         * does not have a default value. Nested maps and nested arrays of maps
1225         * will be recursively synthesized into nested annotations or nested
1226         * arrays of annotations, respectively.
1227         * <p>Note that {@link AnnotationAttributes} is a specialized type of
1228         * {@link Map} that is an ideal candidate for this method's
1229         * {@code attributes} argument.
1230         * @param attributes the map of annotation attributes to synthesize
1231         * @param annotationType the type of annotation to synthesize
1232         * @param annotatedElement the element that is annotated with the annotation
1233         * corresponding to the supplied attributes; may be {@code null} if unknown
1234         * @return the synthesized annotation
1235         * @throws IllegalArgumentException if a required attribute is missing or if an
1236         * attribute is not of the correct type
1237         * @throws AnnotationConfigurationException if invalid configuration of
1238         * {@code @AliasFor} is detected
1239         * @since 4.2
1240         * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
1241         * @see #synthesizeAnnotation(Class)
1242         * @see #getAnnotationAttributes(AnnotatedElement, Annotation)
1243         * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
1244         */
1245        public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes,
1246                        Class<A> annotationType, @Nullable AnnotatedElement annotatedElement) {
1247
1248                try {
1249                        return MergedAnnotation.of(annotatedElement, annotationType, attributes).synthesize();
1250                }
1251                catch (NoSuchElementException | IllegalStateException ex) {
1252                        throw new IllegalArgumentException(ex);
1253                }
1254        }
1255
1256        /**
1257         * <em>Synthesize</em> an array of annotations from the supplied array
1258         * of {@code annotations} by creating a new array of the same size and
1259         * type and populating it with {@linkplain #synthesizeAnnotation(Annotation,
1260         * AnnotatedElement) synthesized} versions of the annotations from the input
1261         * array.
1262         * @param annotations the array of annotations to synthesize
1263         * @param annotatedElement the element that is annotated with the supplied
1264         * array of annotations; may be {@code null} if unknown
1265         * @return a new array of synthesized annotations, or {@code null} if
1266         * the supplied array is {@code null}
1267         * @throws AnnotationConfigurationException if invalid configuration of
1268         * {@code @AliasFor} is detected
1269         * @since 4.2
1270         * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
1271         * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
1272         */
1273        static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, AnnotatedElement annotatedElement) {
1274                if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement)) {
1275                        return annotations;
1276                }
1277                Annotation[] synthesized = (Annotation[]) Array.newInstance(
1278                                annotations.getClass().getComponentType(), annotations.length);
1279                for (int i = 0; i < annotations.length; i++) {
1280                        synthesized[i] = synthesizeAnnotation(annotations[i], annotatedElement);
1281                }
1282                return synthesized;
1283        }
1284
1285        /**
1286         * Clear the internal annotation metadata cache.
1287         * @since 4.3.15
1288         */
1289        public static void clearCache() {
1290                AnnotationTypeMappings.clearCache();
1291                AnnotationsScanner.clearCache();
1292        }
1293
1294
1295        /**
1296         * Internal holder used to wrap default values.
1297         */
1298        private static class DefaultValueHolder {
1299
1300                final Object defaultValue;
1301
1302                public DefaultValueHolder(Object defaultValue) {
1303                        this.defaultValue = defaultValue;
1304                }
1305
1306                @Override
1307                public String toString() {
1308                        return "*" + this.defaultValue;
1309                }
1310        }
1311
1312}