org.springframework.core.annotation.AnnotatedElementUtils Maven / Gradle / Ivy
/*
* Copyright 2002-2018 the original author or authors.
*
* 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;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* General utility methods for finding annotations, meta-annotations, and
* repeatable annotations on {@link AnnotatedElement AnnotatedElements}.
*
* {@code AnnotatedElementUtils} defines the public API for Spring's
* meta-annotation programming model with support for annotation attribute
* overrides. If you do not need support for annotation attribute
* overrides, consider using {@link AnnotationUtils} instead.
*
*
Note that the features of this class are not provided by the JDK's
* introspection facilities themselves.
*
*
Annotation Attribute Overrides
* Support for meta-annotations with attribute overrides in
* composed annotations is provided by all variants of the
* {@code getMergedAnnotationAttributes()}, {@code getMergedAnnotation()},
* {@code getAllMergedAnnotations()}, {@code getMergedRepeatableAnnotations()},
* {@code findMergedAnnotationAttributes()}, {@code findMergedAnnotation()},
* {@code findAllMergedAnnotations()}, and {@code findMergedRepeatableAnnotations()}
* methods.
*
*
Find vs. Get Semantics
* The search algorithms used by methods in this class follow either
* find or get semantics. Consult the javadocs for each
* individual method for details on which search algorithm is used.
*
*
Get semantics are limited to searching for annotations
* that are either present on an {@code AnnotatedElement} (i.e. declared
* locally or {@linkplain java.lang.annotation.Inherited inherited}) or declared
* within the annotation hierarchy above the {@code AnnotatedElement}.
*
*
Find semantics are much more exhaustive, providing
* get semantics plus support for the following:
*
*
* - Searching on interfaces, if the annotated element is a class
*
- Searching on superclasses, if the annotated element is a class
*
- Resolving bridged methods, if the annotated element is a method
*
- Searching on methods in interfaces, if the annotated element is a method
*
- Searching on methods in superclasses, if the annotated element is a method
*
*
* Support for {@code @Inherited}
* Methods following get semantics will honor the contract of 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 find semantics
* will completely ignore the presence of {@code @Inherited} since the find
* search algorithm manually traverses type and method hierarchies and thereby
* implicitly supports annotation inheritance without a need for {@code @Inherited}.
*
* @author Phillip Webb
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.0
* @see AliasFor
* @see AnnotationAttributes
* @see AnnotationUtils
* @see BridgeMethodResolver
*/
public abstract class AnnotatedElementUtils {
/**
* {@code null} constant used to denote that the search algorithm should continue.
*/
@Nullable
private static final Boolean CONTINUE = null;
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
private static final Processor alwaysTrueAnnotationProcessor = new AlwaysTrueBooleanAnnotationProcessor();
/**
* Build an adapted {@link AnnotatedElement} for the given annotations,
* typically for use with other methods on {@link AnnotatedElementUtils}.
* @param annotations the annotations to expose through the {@code AnnotatedElement}
* @since 4.3
*/
public static AnnotatedElement forAnnotations(final Annotation... annotations) {
return new AnnotatedElement() {
@Override
@SuppressWarnings("unchecked")
@Nullable
public T getAnnotation(Class annotationClass) {
for (Annotation ann : annotations) {
if (ann.annotationType() == annotationClass) {
return (T) ann;
}
}
return null;
}
@Override
public Annotation[] getAnnotations() {
return annotations;
}
@Override
public Annotation[] getDeclaredAnnotations() {
return annotations;
}
};
}
/**
* Get the fully qualified class names of all meta-annotation types
* present on the annotation (of the specified {@code annotationType})
* on the supplied {@link AnnotatedElement}.
* This method follows get semantics as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or {@code null} if not found
* @since 4.2
* @see #getMetaAnnotationTypes(AnnotatedElement, String)
* @see #hasMetaAnnotationTypes
*/
public static Set getMetaAnnotationTypes(AnnotatedElement element, Class annotationType) {
return getMetaAnnotationTypes(element, element.getAnnotation(annotationType));
}
/**
* Get the fully qualified class names of all meta-annotation
* types present on the annotation (of the specified
* {@code annotationName}) on the supplied {@link AnnotatedElement}.
* This method follows get semantics as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation
* type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or an empty set if none found
* @see #getMetaAnnotationTypes(AnnotatedElement, Class)
* @see #hasMetaAnnotationTypes
*/
public static Set getMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
return getMetaAnnotationTypes(element, AnnotationUtils.getAnnotation(element, annotationName));
}
private static Set getMetaAnnotationTypes(AnnotatedElement element, @Nullable Annotation composed) {
if (composed == null) {
return Collections.emptySet();
}
try {
final Set types = new LinkedHashSet<>();
searchWithGetSemantics(composed.annotationType(), Collections.emptySet(), null, null, new SimpleAnnotationProcessor