001/* 002 * Copyright 2002-2019 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.type; 018 019import java.lang.annotation.Annotation; 020import java.util.Map; 021 022import org.springframework.core.annotation.MergedAnnotation; 023import org.springframework.core.annotation.MergedAnnotation.Adapt; 024import org.springframework.core.annotation.MergedAnnotationCollectors; 025import org.springframework.core.annotation.MergedAnnotationPredicates; 026import org.springframework.core.annotation.MergedAnnotationSelectors; 027import org.springframework.core.annotation.MergedAnnotations; 028import org.springframework.lang.Nullable; 029import org.springframework.util.MultiValueMap; 030 031/** 032 * Defines access to the annotations of a specific type ({@link AnnotationMetadata class} 033 * or {@link MethodMetadata method}), in a form that does not necessarily require the 034 * class-loading. 035 * 036 * @author Juergen Hoeller 037 * @author Mark Fisher 038 * @author Mark Pollack 039 * @author Chris Beams 040 * @author Phillip Webb 041 * @author Sam Brannen 042 * @since 4.0 043 * @see AnnotationMetadata 044 * @see MethodMetadata 045 */ 046public interface AnnotatedTypeMetadata { 047 048 /** 049 * Return annotation details based on the direct annotations of the 050 * underlying element. 051 * @return merged annotations based on the direct annotations 052 * @since 5.2 053 */ 054 MergedAnnotations getAnnotations(); 055 056 /** 057 * Determine whether the underlying element has an annotation or meta-annotation 058 * of the given type defined. 059 * <p>If this method returns {@code true}, then 060 * {@link #getAnnotationAttributes} will return a non-null Map. 061 * @param annotationName the fully qualified class name of the annotation 062 * type to look for 063 * @return whether a matching annotation is defined 064 */ 065 default boolean isAnnotated(String annotationName) { 066 return getAnnotations().isPresent(annotationName); 067 } 068 069 /** 070 * Retrieve the attributes of the annotation of the given type, if any (i.e. if 071 * defined on the underlying element, as direct annotation or meta-annotation), 072 * also taking attribute overrides on composed annotations into account. 073 * @param annotationName the fully qualified class name of the annotation 074 * type to look for 075 * @return a Map of attributes, with the attribute name as key (e.g. "value") 076 * and the defined attribute value as Map value. This return value will be 077 * {@code null} if no matching annotation is defined. 078 */ 079 @Nullable 080 default Map<String, Object> getAnnotationAttributes(String annotationName) { 081 return getAnnotationAttributes(annotationName, false); 082 } 083 084 /** 085 * Retrieve the attributes of the annotation of the given type, if any (i.e. if 086 * defined on the underlying element, as direct annotation or meta-annotation), 087 * also taking attribute overrides on composed annotations into account. 088 * @param annotationName the fully qualified class name of the annotation 089 * type to look for 090 * @param classValuesAsString whether to convert class references to String 091 * class names for exposure as values in the returned Map, instead of Class 092 * references which might potentially have to be loaded first 093 * @return a Map of attributes, with the attribute name as key (e.g. "value") 094 * and the defined attribute value as Map value. This return value will be 095 * {@code null} if no matching annotation is defined. 096 */ 097 @Nullable 098 default Map<String, Object> getAnnotationAttributes(String annotationName, 099 boolean classValuesAsString) { 100 101 MergedAnnotation<Annotation> annotation = getAnnotations().get(annotationName, 102 null, MergedAnnotationSelectors.firstDirectlyDeclared()); 103 if (!annotation.isPresent()) { 104 return null; 105 } 106 return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true)); 107 } 108 109 /** 110 * Retrieve all attributes of all annotations of the given type, if any (i.e. if 111 * defined on the underlying element, as direct annotation or meta-annotation). 112 * Note that this variant does <i>not</i> take attribute overrides into account. 113 * @param annotationName the fully qualified class name of the annotation 114 * type to look for 115 * @return a MultiMap of attributes, with the attribute name as key (e.g. "value") 116 * and a list of the defined attribute values as Map value. This return value will 117 * be {@code null} if no matching annotation is defined. 118 * @see #getAllAnnotationAttributes(String, boolean) 119 */ 120 @Nullable 121 default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) { 122 return getAllAnnotationAttributes(annotationName, false); 123 } 124 125 /** 126 * Retrieve all attributes of all annotations of the given type, if any (i.e. if 127 * defined on the underlying element, as direct annotation or meta-annotation). 128 * Note that this variant does <i>not</i> take attribute overrides into account. 129 * @param annotationName the fully qualified class name of the annotation 130 * type to look for 131 * @param classValuesAsString whether to convert class references to String 132 * @return a MultiMap of attributes, with the attribute name as key (e.g. "value") 133 * and a list of the defined attribute values as Map value. This return value will 134 * be {@code null} if no matching annotation is defined. 135 * @see #getAllAnnotationAttributes(String) 136 */ 137 @Nullable 138 default MultiValueMap<String, Object> getAllAnnotationAttributes( 139 String annotationName, boolean classValuesAsString) { 140 141 Adapt[] adaptations = Adapt.values(classValuesAsString, true); 142 return getAnnotations().stream(annotationName) 143 .filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)) 144 .map(MergedAnnotation::withNonMergedAttributes) 145 .collect(MergedAnnotationCollectors.toMultiValueMap(map -> 146 map.isEmpty() ? null : map, adaptations)); 147 } 148 149}