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.annotation.Inherited; 021import java.lang.reflect.AnnotatedElement; 022import java.lang.reflect.Method; 023import java.util.Collection; 024import java.util.function.Predicate; 025import java.util.stream.Stream; 026 027import org.springframework.lang.Nullable; 028import org.springframework.util.Assert; 029 030/** 031 * Provides access to a collection of merged annotations, usually obtained 032 * from a source such as a {@link Class} or {@link Method}. 033 * 034 * <p>Each merged annotation represents a view where the attribute values may be 035 * "merged" from different source values, typically: 036 * 037 * <ul> 038 * <li>Explicit and Implicit {@link AliasFor @AliasFor} declarations on one or 039 * more attributes within the annotation</li> 040 * <li>Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation</li> 041 * <li>Convention based attribute aliases for a meta-annotation</li> 042 * <li>From a meta-annotation declaration</li> 043 * </ul> 044 * 045 * <p>For example, a {@code @PostMapping} annotation might be defined as follows: 046 * 047 * <pre class="code"> 048 * @Retention(RetentionPolicy.RUNTIME) 049 * @RequestMapping(method = RequestMethod.POST) 050 * public @interface PostMapping { 051 * 052 * @AliasFor(attribute = "path") 053 * String[] value() default {}; 054 * 055 * @AliasFor(attribute = "value") 056 * String[] path() default {}; 057 * } 058 * </pre> 059 * 060 * <p>If a method is annotated with {@code @PostMapping("/home")} it will contain 061 * merged annotations for both {@code @PostMapping} and the meta-annotation 062 * {@code @RequestMapping}. The merged view of the {@code @RequestMapping} 063 * annotation will contain the following attributes: 064 * 065 * <p><table border="1"> 066 * <tr> 067 * <th>Name</th> 068 * <th>Value</th> 069 * <th>Source</th> 070 * </tr> 071 * <tr> 072 * <td>value</td> 073 * <td>"/home"</td> 074 * <td>Declared in {@code @PostMapping}</td> 075 * </tr> 076 * <tr> 077 * <td>path</td> 078 * <td>"/home"</td> 079 * <td>Explicit {@code @AliasFor}</td> 080 * </tr> 081 * <tr> 082 * <td>method</td> 083 * <td>RequestMethod.POST</td> 084 * <td>Declared in meta-annotation</td> 085 * </tr> 086 * </table> 087 * 088 * <p>{@link MergedAnnotations} can be obtained {@linkplain #from(AnnotatedElement) 089 * from} any Java {@link AnnotatedElement}. They may also be used for sources that 090 * don't use reflection (such as those that directly parse bytecode). 091 * 092 * <p>Different {@linkplain SearchStrategy search strategies} can be used to locate 093 * related source elements that contain the annotations to be aggregated. For 094 * example, {@link SearchStrategy#TYPE_HIERARCHY} will search both superclasses and 095 * implemented interfaces. 096 * 097 * <p>From a {@link MergedAnnotations} instance you can either 098 * {@linkplain #get(String) get} a single annotation, or {@linkplain #stream() 099 * stream all annotations} or just those that match {@linkplain #stream(String) 100 * a specific type}. You can also quickly tell if an annotation 101 * {@linkplain #isPresent(String) is present}. 102 * 103 * <p>Here are some typical examples: 104 * 105 * <pre class="code"> 106 * // is an annotation present or meta-present? 107 * mergedAnnotations.isPresent(ExampleAnnotation.class); 108 * 109 * // get the merged "value" attribute of ExampleAnnotation (either directly or 110 * // meta-present) 111 * mergedAnnotations.get(ExampleAnnotation.class).getString("value"); 112 * 113 * // get all meta-annotations but no directly present annotations 114 * mergedAnnotations.stream().filter(MergedAnnotation::isMetaPresent); 115 * 116 * // get all ExampleAnnotation declarations (including any meta-annotations) and 117 * // print the merged "value" attributes 118 * mergedAnnotations.stream(ExampleAnnotation.class) 119 * .map(mergedAnnotation -> mergedAnnotation.getString("value")) 120 * .forEach(System.out::println); 121 * </pre> 122 * 123 * <p><b>NOTE: The {@code MergedAnnotations} API and its underlying model have 124 * been designed for composable annotations in Spring's common component model, 125 * with a focus on attribute aliasing and meta-annotation relationships.</b> 126 * There is no support for retrieving plain Java annotations with this API; 127 * please use standard Java reflection or Spring's {@link AnnotationUtils} 128 * for simple annotation retrieval purposes. 129 * 130 * @author Phillip Webb 131 * @author Sam Brannen 132 * @since 5.2 133 * @see MergedAnnotation 134 * @see MergedAnnotationCollectors 135 * @see MergedAnnotationPredicates 136 * @see MergedAnnotationSelectors 137 */ 138public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>> { 139 140 /** 141 * Determine if the specified annotation is either directly present or 142 * meta-present. 143 * <p>Equivalent to calling {@code get(annotationType).isPresent()}. 144 * @param annotationType the annotation type to check 145 * @return {@code true} if the annotation is present 146 */ 147 <A extends Annotation> boolean isPresent(Class<A> annotationType); 148 149 /** 150 * Determine if the specified annotation is either directly present or 151 * meta-present. 152 * <p>Equivalent to calling {@code get(annotationType).isPresent()}. 153 * @param annotationType the fully qualified class name of the annotation type 154 * to check 155 * @return {@code true} if the annotation is present 156 */ 157 boolean isPresent(String annotationType); 158 159 /** 160 * Determine if the specified annotation is directly present. 161 * <p>Equivalent to calling {@code get(annotationType).isDirectlyPresent()}. 162 * @param annotationType the annotation type to check 163 * @return {@code true} if the annotation is directly present 164 */ 165 <A extends Annotation> boolean isDirectlyPresent(Class<A> annotationType); 166 167 /** 168 * Determine if the specified annotation is directly present. 169 * <p>Equivalent to calling {@code get(annotationType).isDirectlyPresent()}. 170 * @param annotationType the fully qualified class name of the annotation type 171 * to check 172 * @return {@code true} if the annotation is directly present 173 */ 174 boolean isDirectlyPresent(String annotationType); 175 176 /** 177 * Get the {@linkplain MergedAnnotationSelectors#nearest() nearest} matching 178 * annotation or meta-annotation of the specified type, or 179 * {@link MergedAnnotation#missing()} if none is present. 180 * @param annotationType the annotation type to get 181 * @return a {@link MergedAnnotation} instance 182 */ 183 <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType); 184 185 /** 186 * Get the {@linkplain MergedAnnotationSelectors#nearest() nearest} matching 187 * annotation or meta-annotation of the specified type, or 188 * {@link MergedAnnotation#missing()} if none is present. 189 * @param annotationType the annotation type to get 190 * @param predicate a predicate that must match, or {@code null} if only 191 * type matching is required 192 * @return a {@link MergedAnnotation} instance 193 * @see MergedAnnotationPredicates 194 */ 195 <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType, 196 @Nullable Predicate<? super MergedAnnotation<A>> predicate); 197 198 /** 199 * Get a matching annotation or meta-annotation of the specified type, or 200 * {@link MergedAnnotation#missing()} if none is present. 201 * @param annotationType the annotation type to get 202 * @param predicate a predicate that must match, or {@code null} if only 203 * type matching is required 204 * @param selector a selector used to choose the most appropriate annotation 205 * within an aggregate, or {@code null} to select the 206 * {@linkplain MergedAnnotationSelectors#nearest() nearest} 207 * @return a {@link MergedAnnotation} instance 208 * @see MergedAnnotationPredicates 209 * @see MergedAnnotationSelectors 210 */ 211 <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType, 212 @Nullable Predicate<? super MergedAnnotation<A>> predicate, 213 @Nullable MergedAnnotationSelector<A> selector); 214 215 /** 216 * Get the {@linkplain MergedAnnotationSelectors#nearest() nearest} matching 217 * annotation or meta-annotation of the specified type, or 218 * {@link MergedAnnotation#missing()} if none is present. 219 * @param annotationType the fully qualified class name of the annotation type 220 * to get 221 * @return a {@link MergedAnnotation} instance 222 */ 223 <A extends Annotation> MergedAnnotation<A> get(String annotationType); 224 225 /** 226 * Get the {@linkplain MergedAnnotationSelectors#nearest() nearest} matching 227 * annotation or meta-annotation of the specified type, or 228 * {@link MergedAnnotation#missing()} if none is present. 229 * @param annotationType the fully qualified class name of the annotation type 230 * to get 231 * @param predicate a predicate that must match, or {@code null} if only 232 * type matching is required 233 * @return a {@link MergedAnnotation} instance 234 * @see MergedAnnotationPredicates 235 */ 236 <A extends Annotation> MergedAnnotation<A> get(String annotationType, 237 @Nullable Predicate<? super MergedAnnotation<A>> predicate); 238 239 /** 240 * Get a matching annotation or meta-annotation of the specified type, or 241 * {@link MergedAnnotation#missing()} if none is present. 242 * @param annotationType the fully qualified class name of the annotation type 243 * to get 244 * @param predicate a predicate that must match, or {@code null} if only 245 * type matching is required 246 * @param selector a selector used to choose the most appropriate annotation 247 * within an aggregate, or {@code null} to select the 248 * {@linkplain MergedAnnotationSelectors#nearest() nearest} 249 * @return a {@link MergedAnnotation} instance 250 * @see MergedAnnotationPredicates 251 * @see MergedAnnotationSelectors 252 */ 253 <A extends Annotation> MergedAnnotation<A> get(String annotationType, 254 @Nullable Predicate<? super MergedAnnotation<A>> predicate, 255 @Nullable MergedAnnotationSelector<A> selector); 256 257 /** 258 * Stream all annotations and meta-annotations that match the specified 259 * type. The resulting stream follows the same ordering rules as 260 * {@link #stream()}. 261 * @param annotationType the annotation type to match 262 * @return a stream of matching annotations 263 */ 264 <A extends Annotation> Stream<MergedAnnotation<A>> stream(Class<A> annotationType); 265 266 /** 267 * Stream all annotations and meta-annotations that match the specified 268 * type. The resulting stream follows the same ordering rules as 269 * {@link #stream()}. 270 * @param annotationType the fully qualified class name of the annotation type 271 * to match 272 * @return a stream of matching annotations 273 */ 274 <A extends Annotation> Stream<MergedAnnotation<A>> stream(String annotationType); 275 276 /** 277 * Stream all annotations and meta-annotations contained in this collection. 278 * The resulting stream is ordered first by the 279 * {@linkplain MergedAnnotation#getAggregateIndex() aggregate index} and then 280 * by the annotation distance (with the closest annotations first). This ordering 281 * means that, for most use-cases, the most suitable annotations appear 282 * earliest in the stream. 283 * @return a stream of annotations 284 */ 285 Stream<MergedAnnotation<Annotation>> stream(); 286 287 288 /** 289 * Create a new {@link MergedAnnotations} instance containing all 290 * annotations and meta-annotations from the specified element. The 291 * resulting instance will not include any inherited annotations. If you 292 * want to include those as well you should use 293 * {@link #from(AnnotatedElement, SearchStrategy)} with an appropriate 294 * {@link SearchStrategy}. 295 * @param element the source element 296 * @return a {@link MergedAnnotations} instance containing the element's 297 * annotations 298 */ 299 static MergedAnnotations from(AnnotatedElement element) { 300 return from(element, SearchStrategy.DIRECT); 301 } 302 303 /** 304 * Create a new {@link MergedAnnotations} instance containing all 305 * annotations and meta-annotations from the specified element and, 306 * depending on the {@link SearchStrategy}, related inherited elements. 307 * @param element the source element 308 * @param searchStrategy the search strategy to use 309 * @return a {@link MergedAnnotations} instance containing the merged 310 * element annotations 311 */ 312 static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy) { 313 return from(element, searchStrategy, RepeatableContainers.standardRepeatables()); 314 } 315 316 /** 317 * Create a new {@link MergedAnnotations} instance containing all 318 * annotations and meta-annotations from the specified element and, 319 * depending on the {@link SearchStrategy}, related inherited elements. 320 * @param element the source element 321 * @param searchStrategy the search strategy to use 322 * @param repeatableContainers the repeatable containers that may be used by 323 * the element annotations or the meta-annotations 324 * @return a {@link MergedAnnotations} instance containing the merged 325 * element annotations 326 */ 327 static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy, 328 RepeatableContainers repeatableContainers) { 329 330 return from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN); 331 } 332 333 /** 334 * Create a new {@link MergedAnnotations} instance containing all 335 * annotations and meta-annotations from the specified element and, 336 * depending on the {@link SearchStrategy}, related inherited elements. 337 * @param element the source element 338 * @param searchStrategy the search strategy to use 339 * @param repeatableContainers the repeatable containers that may be used by 340 * the element annotations or the meta-annotations 341 * @param annotationFilter an annotation filter used to restrict the 342 * annotations considered 343 * @return a {@link MergedAnnotations} instance containing the merged 344 * annotations for the supplied element 345 */ 346 static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy, 347 RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { 348 349 Assert.notNull(repeatableContainers, "RepeatableContainers must not be null"); 350 Assert.notNull(annotationFilter, "AnnotationFilter must not be null"); 351 return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, annotationFilter); 352 } 353 354 /** 355 * Create a new {@link MergedAnnotations} instance from the specified 356 * annotations. 357 * @param annotations the annotations to include 358 * @return a {@link MergedAnnotations} instance containing the annotations 359 * @see #from(Object, Annotation...) 360 */ 361 static MergedAnnotations from(Annotation... annotations) { 362 return from(annotations, annotations); 363 } 364 365 /** 366 * Create a new {@link MergedAnnotations} instance from the specified 367 * annotations. 368 * @param source the source for the annotations. This source is used only 369 * for information and logging. It does not need to <em>actually</em> 370 * contain the specified annotations, and it will not be searched. 371 * @param annotations the annotations to include 372 * @return a {@link MergedAnnotations} instance containing the annotations 373 * @see #from(Annotation...) 374 * @see #from(AnnotatedElement) 375 */ 376 static MergedAnnotations from(Object source, Annotation... annotations) { 377 return from(source, annotations, RepeatableContainers.standardRepeatables()); 378 } 379 380 /** 381 * Create a new {@link MergedAnnotations} instance from the specified 382 * annotations. 383 * @param source the source for the annotations. This source is used only 384 * for information and logging. It does not need to <em>actually</em> 385 * contain the specified annotations, and it will not be searched. 386 * @param annotations the annotations to include 387 * @param repeatableContainers the repeatable containers that may be used by 388 * meta-annotations 389 * @return a {@link MergedAnnotations} instance containing the annotations 390 */ 391 static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers) { 392 return from(source, annotations, repeatableContainers, AnnotationFilter.PLAIN); 393 } 394 395 /** 396 * Create a new {@link MergedAnnotations} instance from the specified 397 * annotations. 398 * @param source the source for the annotations. This source is used only 399 * for information and logging. It does not need to <em>actually</em> 400 * contain the specified annotations, and it will not be searched. 401 * @param annotations the annotations to include 402 * @param repeatableContainers the repeatable containers that may be used by 403 * meta-annotations 404 * @param annotationFilter an annotation filter used to restrict the 405 * annotations considered 406 * @return a {@link MergedAnnotations} instance containing the annotations 407 */ 408 static MergedAnnotations from(Object source, Annotation[] annotations, 409 RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { 410 411 Assert.notNull(repeatableContainers, "RepeatableContainers must not be null"); 412 Assert.notNull(annotationFilter, "AnnotationFilter must not be null"); 413 return TypeMappedAnnotations.from(source, annotations, repeatableContainers, annotationFilter); 414 } 415 416 /** 417 * Create a new {@link MergedAnnotations} instance from the specified 418 * collection of directly present annotations. This method allows a 419 * {@link MergedAnnotations} instance to be created from annotations that 420 * are not necessarily loaded using reflection. The provided annotations 421 * must all be {@link MergedAnnotation#isDirectlyPresent() directly present} 422 * and must have an {@link MergedAnnotation#getAggregateIndex() aggregate 423 * index} of {@code 0}. 424 * <p>The resulting {@link MergedAnnotations} instance will contain both the 425 * specified annotations, and any meta-annotations that can be read using 426 * reflection. 427 * @param annotations the annotations to include 428 * @return a {@link MergedAnnotations} instance containing the annotations 429 * @see MergedAnnotation#of(ClassLoader, Object, Class, java.util.Map) 430 */ 431 static MergedAnnotations of(Collection<MergedAnnotation<?>> annotations) { 432 return MergedAnnotationsCollection.of(annotations); 433 } 434 435 436 /** 437 * Search strategies supported by 438 * {@link MergedAnnotations#from(AnnotatedElement, SearchStrategy)}. 439 * 440 * <p>Each strategy creates a different set of aggregates that will be 441 * combined to create the final {@link MergedAnnotations}. 442 */ 443 enum SearchStrategy { 444 445 /** 446 * Find only directly declared annotations, without considering 447 * {@link Inherited @Inherited} annotations and without searching 448 * superclasses or implemented interfaces. 449 */ 450 DIRECT, 451 452 /** 453 * Find all directly declared annotations as well as any 454 * {@link Inherited @Inherited} superclass annotations. This strategy 455 * is only really useful when used with {@link Class} types since the 456 * {@link Inherited @Inherited} annotation is ignored for all other 457 * {@linkplain AnnotatedElement annotated elements}. This strategy does 458 * not search implemented interfaces. 459 */ 460 INHERITED_ANNOTATIONS, 461 462 /** 463 * Find all directly declared and superclass annotations. This strategy 464 * is similar to {@link #INHERITED_ANNOTATIONS} except the annotations 465 * do not need to be meta-annotated with {@link Inherited @Inherited}. 466 * This strategy does not search implemented interfaces. 467 */ 468 SUPERCLASS, 469 470 /** 471 * Perform a full search of the entire type hierarchy, including 472 * superclasses and implemented interfaces. Superclass annotations do 473 * not need to be meta-annotated with {@link Inherited @Inherited}. 474 */ 475 TYPE_HIERARCHY, 476 477 /** 478 * Perform a full search of the entire type hierarchy on the source 479 * <em>and</em> any enclosing classes. This strategy is similar to 480 * {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass() 481 * enclosing classes} are also searched. Superclass annotations do not 482 * need to be meta-annotated with {@link Inherited @Inherited}. When 483 * searching a {@link Method} source, this strategy is identical to 484 * {@link #TYPE_HIERARCHY}. 485 */ 486 TYPE_HIERARCHY_AND_ENCLOSING_CLASSES 487 } 488 489}