001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.reflect; 018 019import static java.util.Collections.*; 020import static org.apache.juneau.commons.reflect.AnnotationTraversal.*; 021import static org.apache.juneau.commons.reflect.ReflectionUtils.*; 022import static org.apache.juneau.commons.utils.Shorts.*; 023import static org.apache.juneau.commons.utils.SystemUtils.*; 024 025import java.lang.annotation.*; 026import java.lang.reflect.*; 027import java.util.*; 028 029import org.apache.juneau.commons.collections.*; 030import org.apache.juneau.commons.lang.*; 031import org.apache.juneau.commons.utils.*; 032 033/** 034 * Enhanced annotation provider that returns {@link AnnotationInfo} objects and supports runtime annotations. 035 * 036 * <p> 037 * This class provides a modern API for retrieving annotations with the following benefits: 038 * <ul> 039 * <li>Returns {@link AnnotationInfo} wrappers that provide additional methods and type safety 040 * <li>Supports filtering by annotation type using streams 041 * <li>Properly handles repeatable annotations 042 * <li>Searches up the class/method hierarchy with well-defined order of precedence 043 * <li>Supports runtime annotations (annotations added programmatically at runtime) 044 * <li>Caches results for performance 045 * </ul> 046 * 047 * <h5 class='section'>Annotation Order of Precedence:</h5> 048 * 049 * <h6 class='topic'>For Classes ({@link #find(Class, ClassInfo, AnnotationTraversal...)}):</h6> 050 * <p> 051 * Annotations are returned in <b>child-to-parent</b> order with the following precedence: 052 * <ol> 053 * <li><b>Runtime annotations</b> on the class (highest priority) 054 * <li><b>Declared annotations</b> on the class 055 * <li><b>Runtime annotations</b> on parent classes (child-to-parent order) 056 * <li><b>Declared annotations</b> on parent classes (child-to-parent order) 057 * <li><b>Runtime annotations</b> on interfaces (child-to-parent order) 058 * <li><b>Declared annotations</b> on interfaces (child-to-parent order) 059 * <li><b>Declared annotations</b> on the package (lowest priority) 060 * </ol> 061 * 062 * <p class='bcode'> 063 * <jc>// Example: Given class Child extends Parent</jc> 064 * <jc>// Annotation order will be:</jc> 065 * <jc>// 1. Runtime annotations on Child</jc> 066 * <jc>// 2. @Annotation on Child</jc> 067 * <jc>// 3. Runtime annotations on Parent</jc> 068 * <jc>// 4. @Annotation on Parent</jc> 069 * <jc>// 5. Runtime annotations on IChild (if Child implements IChild)</jc> 070 * <jc>// 6. @Annotation on IChild</jc> 071 * <jc>// 7. @Annotation on package-info.java</jc> 072 * </p> 073 * 074 * <h6 class='topic'>For Methods ({@link #find(Class, MethodInfo, AnnotationTraversal...)}):</h6> 075 * <p> 076 * Annotations are returned in <b>child-to-parent</b> order with the following precedence: 077 * <ol> 078 * <li><b>Runtime annotations</b> on the method (highest priority) 079 * <li><b>Declared annotations</b> on the method 080 * <li><b>Runtime annotations</b> on overridden parent methods (child-to-parent order) 081 * <li><b>Declared annotations</b> on overridden parent methods (child-to-parent order) 082 * </ol> 083 * 084 * <h6 class='topic'>For Fields ({@link #find(Class, FieldInfo, AnnotationTraversal...)}):</h6> 085 * <p> 086 * Annotations are returned with the following precedence: 087 * <ol> 088 * <li><b>Runtime annotations</b> on the field (highest priority) 089 * <li><b>Declared annotations</b> on the field 090 * </ol> 091 * 092 * <h6 class='topic'>For Constructors ({@link #find(Class, ConstructorInfo, AnnotationTraversal...)}):</h6> 093 * <p> 094 * Annotations are returned with the following precedence: 095 * <ol> 096 * <li><b>Runtime annotations</b> on the constructor (highest priority) 097 * <li><b>Declared annotations</b> on the constructor 098 * </ol> 099 * 100 * <h5 class='section'>Runtime Annotations:</h5> 101 * <p> 102 * Runtime annotations are concrete objects that implement annotation interfaces, added programmatically via the 103 * builder's {@link Builder#addRuntimeAnnotations(List)} method. They allow you to dynamically apply annotations 104 * to classes, methods, fields, and constructors at runtime without modifying source code. 105 * 106 * <p> 107 * <b>How Runtime Annotations Work:</b> 108 * <ul> 109 * <li>Runtime annotations are Java objects that implement annotation interfaces (e.g., {@code @Marshalled}) 110 * <li>They use special methods like {@code on()} or {@code onClass()} to specify their targets 111 * <li>They always take precedence over declared annotations at the same level 112 * <li>They are particularly useful for applying annotations to classes you don't control 113 * </ul> 114 * 115 * <p class='bjava'> 116 * <jc>// Example: Creating a runtime annotation</jc> 117 * Bean <jv>runtimeAnnotation</jv> = MarshalledAnnotation 118 * .<jsm>create</jsm>() 119 * .onClass(MyClass.<jk>class</jk>) <jc>// Target class</jc> 120 * .typeName(<js>"MyType"</js>) <jc>// Annotation property</jc> 121 * .build(); 122 * 123 * <jc>// Add to provider</jc> 124 * AnnotationProvider <jv>provider</jv> = AnnotationProvider 125 * .<jsm>create</jsm>() 126 * .addRuntimeAnnotations(<jv>runtimeAnnotation</jv>) 127 * .build(); 128 * 129 * <jc>// Now MyClass will be found with @Marshalled annotation</jc> 130 * Stream<AnnotationInfo<Bean>> <jv>annotations</jv> = <jv>provider</jv>.find(Bean.<jk>class</jk>, MyClass.<jk>class</jk>); 131 * </p> 132 * 133 * <p> 134 * <b>Targeting Methods:</b> 135 * <ul> 136 * <li>{@code on()} - String array of fully-qualified names (e.g., {@code "com.example.MyClass.myMethod"}) 137 * <li>{@code onClass()} - Class array for type-safe targeting 138 * </ul> 139 * 140 * <p> 141 * Runtime annotations are evaluated before declared annotations at each level, giving them higher priority. 142 * For example, a runtime {@code @Marshalled} annotation on a class will be found before any {@code @Marshalled} annotation 143 * declared directly on that class. 144 * 145 * <h5 class='section'>Comparison with ElementInfo Methods:</h5> 146 * <p> 147 * The methods in this class differ from {@link ClassInfo#getAnnotations()}, {@link MethodInfo#getAnnotations()}, etc.: 148 * <ul> 149 * <li><b>Runtime Annotations</b>: ElementInfo methods return ONLY declared annotations. This class includes runtime annotations. 150 * <li><b>Hierarchy</b>: ElementInfo methods may have different traversal logic. This class uses a consistent approach. 151 * <li><b>Precedence</b>: Runtime annotations are inserted at each level with higher priority than declared annotations. 152 * </ul> 153 * 154 * <h5 class='section'>Usage:</h5> 155 * <p class='bjava'> 156 * <jc>// Create with default settings</jc> 157 * AnnotationProvider <jv>provider</jv> = AnnotationProvider.<jsm>create</jsm>().build(); 158 * 159 * <jc>// Create with runtime annotations</jc> 160 * AnnotationProvider <jv>provider</jv> = AnnotationProvider 161 * .<jsm>create</jsm>() 162 * .annotations(<jk>new</jk> MyAnnotationImpl()) 163 * .build(); 164 * 165 * <jc>// Find all annotations on a class</jc> 166 * List<AnnotationInfo<Annotation>> <jv>annotations</jv> = <jv>provider</jv>.find(MyClass.<jk>class</jk>); 167 * 168 * <jc>// Find specific annotation type on a class</jc> 169 * Stream<AnnotationInfo<MyAnnotation>> <jv>myAnnotations</jv> = <jv>provider</jv>.find(MyAnnotation.<jk>class</jk>, MyClass.<jk>class</jk>); 170 * </p> 171 * 172 * <h5 class='section'>See Also:</h5> 173 * <ul> 174 * <li class='jc'>{@link AnnotationProvider} 175 * <li class='jc'>{@link AnnotationInfo} 176 * <li class='jc'>{@link ClassInfo} 177 * <li class='jc'>{@link MethodInfo} 178 * </ul> 179 */ 180@SuppressWarnings({ 181 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 182 "java:S1452", // Wildcard required - List<AnnotationInfo<? extends Annotation>> for heterogeneous annotations 183 "java:S3776", // load() and the find()/has() lookups combine traversal order, type filtering and caching in a single pass 184 "rawtypes", // Raw types necessary for generic type handling 185 "unchecked" // Type erasure requires unchecked casts 186}) 187public class AnnotationProvider { 188 189 //----------------------------------------------------------------------------------------------------------------- 190 // System properties 191 //----------------------------------------------------------------------------------------------------------------- 192 193 /** 194 * Builder for creating configured {@link AnnotationProvider} instances. 195 * 196 * <h5 class='section'>Example:</h5> 197 * <p class='bjava'> 198 * AnnotationProvider <jv>provider</jv> = AnnotationProvider 199 * .<jsm>create</jsm>() 200 * .disableCaching() 201 * .build(); 202 * </p> 203 * 204 * <h5 class='section'>See Also:</h5> 205 * <ul> 206 * <li class='jm'>{@link AnnotationProvider#create()} 207 * </ul> 208 */ 209 public static class Builder { 210 CacheMode cacheMode; 211 boolean logOnExit; 212 ReflectionMap.Builder<Annotation> runtimeAnnotations; 213 214 Builder() { 215 cacheMode = CACHING_MODE; 216 logOnExit = LOG_ON_EXIT; 217 } 218 219 /** 220 * Adds runtime annotations to be applied to classes, methods, fields, and constructors. 221 * 222 * <p> 223 * This is a convenience method that delegates to {@link #addRuntimeAnnotations(List)}. 224 * See that method for detailed documentation on how runtime annotations work. 225 * 226 * <p class='bjava'> 227 * <jc>// Example: Add multiple runtime annotations using varargs</jc> 228 * Bean <jv>beanAnnotation</jv> = MarshalledAnnotation 229 * .<jsm>create</jsm>() 230 * .onClass(MyClass.<jk>class</jk>) 231 * .typeName(<js>"MyType"</js>) 232 * .build(); 233 * 234 * Swap <jv>swapAnnotation</jv> = SwapAnnotation 235 * .<jsm>create</jsm>() 236 * .on(<js>"com.example.MyClass.getValue"</js>) 237 * .value(MySwap.<jk>class</jk>) 238 * .build(); 239 * 240 * AnnotationProvider <jv>provider</jv> = AnnotationProvider 241 * .<jsm>create</jsm>() 242 * .addRuntimeAnnotations(<jv>beanAnnotation</jv>, <jv>swapAnnotation</jv>) <jc>// Varargs</jc> 243 * .build(); 244 * </p> 245 * 246 * @param annotations The runtime annotation objects to add (varargs). 247 * @return This object for method chaining. 248 * @throws BeanRuntimeException If any annotation is invalid. 249 * @see #addRuntimeAnnotations(List) 250 */ 251 public Builder addRuntimeAnnotations(Annotation...annotations) { 252 return addRuntimeAnnotations(l(annotations)); 253 } 254 255 /** 256 * Adds runtime annotations to be applied to classes, methods, fields, and constructors. 257 * 258 * <p> 259 * Runtime annotations are concrete Java objects that implement annotation interfaces (e.g., {@code @Marshalled}). 260 * They allow you to dynamically apply annotations to code elements at runtime without modifying source code. 261 * 262 * <p> 263 * <b>How It Works:</b> 264 * <ol> 265 * <li>Create annotation objects using builder classes (e.g., {@code MarshalledAnnotation.create()}) 266 * <li>Specify targets using {@code on()} or {@code onClass()} methods 267 * <li>Set annotation properties (e.g., {@code typeName()}, {@code properties()}) 268 * <li>Build the annotation object 269 * <li>Add to the provider via this method 270 * </ol> 271 * 272 * <p> 273 * <b>Targeting Requirements:</b> 274 * <ul> 275 * <li>Annotations MUST define an {@code onClass()} method returning {@code Class[]} for type-safe targeting 276 * <li>OR an {@code on()} method returning {@code String[]} for string-based targeting 277 * <li>The {@code on()} method accepts fully-qualified names: 278 * <ul> 279 * <li>{@code "com.example.MyClass"} - targets a class 280 * <li>{@code "com.example.MyClass.myMethod"} - targets a method 281 * <li>{@code "com.example.MyClass.myField"} - targets a field 282 * </ul> 283 * </ul> 284 * 285 * <p class='bjava'> 286 * <jc>// Example 1: Target a specific class using type-safe targeting</jc> 287 * Bean <jv>beanAnnotation</jv> = MarshalledAnnotation 288 * .<jsm>create</jsm>() 289 * .onClass(MyClass.<jk>class</jk>) <jc>// Targets MyClass</jc> 290 * .typeName(<js>"MyType"</js>) 291 * .properties(<js>"id,name"</js>) 292 * .build(); 293 * 294 * <jc>// Example 2: Target multiple classes</jc> 295 * Bean <jv>multiAnnotation</jv> = MarshalledAnnotation 296 * .<jsm>create</jsm>() 297 * .onClass(MyClass.<jk>class</jk>, OtherClass.<jk>class</jk>) 298 * .sort(<jk>true</jk>) 299 * .build(); 300 * 301 * <jc>// Example 3: Target using string names (useful for dynamic/reflection scenarios)</jc> 302 * Bean <jv>stringAnnotation</jv> = MarshalledAnnotation 303 * .<jsm>create</jsm>() 304 * .on(<js>"com.example.MyClass"</js>) 305 * .findFluentSetters(<jk>true</jk>) 306 * .build(); 307 * 308 * <jc>// Example 4: Target a specific method</jc> 309 * Swap <jv>swapAnnotation</jv> = SwapAnnotation 310 * .<jsm>create</jsm>() 311 * .on(<js>"com.example.MyClass.getValue"</js>) 312 * .value(MySwap.<jk>class</jk>) 313 * .build(); 314 * 315 * <jc>// Add all runtime annotations to the provider</jc> 316 * AnnotationProvider <jv>provider</jv> = AnnotationProvider 317 * .<jsm>create</jsm>() 318 * .addRuntimeAnnotations(<jv>beanAnnotation</jv>, <jv>multiAnnotation</jv>, <jv>stringAnnotation</jv>, <jv>swapAnnotation</jv>) 319 * .build(); 320 * </p> 321 * 322 * <p> 323 * <b>Priority:</b> Runtime annotations always take precedence over declared annotations at the same level. 324 * They are evaluated first when searching for annotations. 325 * 326 * @param annotations The list of runtime annotation objects to add. 327 * @return This object for method chaining. 328 * @throws BeanRuntimeException If any annotation is invalid (missing {@code on()} or {@code onClass()} methods, 329 * or if the methods return incorrect types). 330 */ 331 public Builder addRuntimeAnnotations(List<Annotation> annotations) { 332 if (runtimeAnnotations == null) 333 runtimeAnnotations = ReflectionMap.create(Annotation.class); 334 335 for (var a : annotations) { 336 try { 337 var ci = ClassInfo.of(a.getClass()); 338 339 // XApply pattern: if annotation has a value() returning a single Annotation, 340 // unwrap and store the inner annotation instead of the wrapper. 341 var annotationToStore = unwrapXApply(ci, a); 342 343 ci.getPublicMethod(x -> x.hasName("onClass")).ifPresent(mi -> { 344 if (! mi.getReturnType().is(Class[].class)) 345 throw brex("Invalid annotation @%s used in runtime annotations. Annotation must define an onClass() method that returns a Class array.", cns(a)); 346 for (var c : (Class<?>[])mi.accessible().invoke(a)) 347 runtimeAnnotations.append(c.getName(), annotationToStore); 348 }); 349 350 ci.getPublicMethod(x -> x.hasName("on")).ifPresent(mi -> { 351 if (! mi.getReturnType().is(String[].class)) 352 throw brex("Invalid annotation @%s used in runtime annotations. Annotation must define an on() method that returns a String array.", cns(a)); 353 for (var s : (String[])mi.accessible().invoke(a)) 354 runtimeAnnotations.append(s, annotationToStore); 355 }); 356 357 } catch (BeanRuntimeException e) { 358 throw e; 359 } catch (Exception e) { 360 throw brex(e, (Class<?>)null, "Invalid annotation @%s used in runtime annotations.", cn(a)); 361 } 362 } 363 return this; 364 } 365 366 private static Annotation unwrapXApply(ClassInfo ci, Annotation a) { 367 var valueMethod = ci.getPublicMethod(x -> x.hasName("value")); 368 if (valueMethod.isEmpty()) 369 return a; 370 var mi = valueMethod.get(); 371 var rt = mi.getReturnType().inner(); 372 if (! Annotation.class.isAssignableFrom(rt) || rt.isArray()) 373 return a; 374 var inner = (Annotation) mi.accessible().invoke(a); 375 return or(inner, a); 376 } 377 378 /** 379 * Builds a new {@link AnnotationProvider} instance with the configured settings. 380 * 381 * @return A new immutable {@link AnnotationProvider} instance. 382 */ 383 public AnnotationProvider build() { 384 if (ie(runtimeAnnotations)) 385 return INSTANCE; 386 return new AnnotationProvider(this); 387 } 388 389 /** 390 * Sets the caching mode for annotation lookups. 391 * 392 * <p> 393 * Available modes: 394 * <ul> 395 * <li><c>NONE</c> - Disables all caching (always recompute) 396 * <li><c>WEAK</c> - Uses WeakHashMap (allows GC of cached entries) 397 * <li><c>FULL</c> - Uses ConcurrentHashMap (best performance) 398 * </ul> 399 * 400 * @param value The caching mode. 401 * @return This object for method chaining. 402 */ 403 public Builder cacheMode(CacheMode value) { 404 cacheMode = value; 405 return this; 406 } 407 408 /** 409 * Enables logging of cache statistics on JVM shutdown. 410 * 411 * @return This object for method chaining. 412 */ 413 public Builder logOnExit() { 414 logOnExit = true; 415 return this; 416 } 417 418 /** 419 * Conditionally enables logging of cache statistics on JVM shutdown. 420 * 421 * @param value Whether to log on exit. 422 * @return This object for method chaining. 423 */ 424 public Builder logOnExit(boolean value) { 425 logOnExit = value; 426 return this; 427 } 428 } 429 430 /** 431 * Caching mode for annotation lookups. 432 * 433 * <p> 434 * System property: <c>juneau.annotationProvider.caching</c> 435 * <br>Valid values: <c>NONE</c>, <c>WEAK</c>, <c>FULL</c> (case-insensitive) 436 * <br>Default: <c>FULL</c> 437 * 438 * <ul> 439 * <li><c>NONE</c> - Disables all caching (always recompute) 440 * <li><c>WEAK</c> - Uses WeakHashMap (allows GC of cached entries) 441 * <li><c>FULL</c> - Uses ConcurrentHashMap (best performance) 442 * </ul> 443 */ 444 private static final CacheMode CACHING_MODE = env("juneau.annotationProvider.caching", CacheMode.FULL); 445 446 /** 447 * Enable logging of cache statistics on JVM shutdown. 448 * 449 * <p> 450 * System property: <c>juneau.annotationProvider.caching.logOnExit</c> 451 * <br>Valid values: <c>TRUE</c>, <c>FALSE</c> (case-insensitive) 452 * <br>Default: <c>FALSE</c> 453 */ 454 private static final boolean LOG_ON_EXIT = env("juneau.annotationProvider.caching.logOnExit", false); 455 456 //----------------------------------------------------------------------------------------------------------------- 457 // Builder 458 //----------------------------------------------------------------------------------------------------------------- 459 460 /** 461 * Default instance. 462 */ 463 public static final AnnotationProvider INSTANCE = new AnnotationProvider(create().logOnExit()); 464 465 /** 466 * Creates a new {@link Builder} for constructing an annotation provider. 467 * 468 * @return A new builder for configuring the annotation provider. 469 */ 470 public static Builder create() { 471 return new Builder(); 472 } 473 474 private static <A extends Annotation> AnnotationInfo<A> ai(Annotatable on, A value) { 475 return AnnotationInfo.of(on, value); 476 } 477 478 private final Cache<Object,List<AnnotationInfo<Annotation>>> runtimeCache; 479 private final Cache3<Class<?>,ElementInfo,AnnotationTraversal[],List> cache; 480 481 private final ReflectionMap<Annotation> annotationMap; 482 483 //----------------------------------------------------------------------------------------------------------------- 484 // Stream-based traversal methods 485 //----------------------------------------------------------------------------------------------------------------- 486 487 /** 488 * Constructor. 489 * 490 * @param builder The builder containing configuration settings. 491 */ 492 protected AnnotationProvider(Builder builder) { 493 // @formatter:off 494 this.runtimeCache = Cache.<Object,List<AnnotationInfo<Annotation>>>create() 495 .supplier(this::load) 496 .cacheMode(builder.cacheMode) 497 .logOnExit(builder.logOnExit, "AnnotationProvider.runtimeAnnotations") 498 .build(); 499 500 this.cache = Cache3.<Class<?>,ElementInfo,AnnotationTraversal[],List>create() 501 .supplier(this::load) 502 .cacheMode(builder.cacheMode) 503 .logOnExit(builder.logOnExit, "AnnotationProvider.cache") 504 .build(); 505 506 this.annotationMap = o(builder.runtimeAnnotations).map(ReflectionMap.Builder::build).orElse(null); 507 // @formatter:on 508 } 509 510 /** 511 * Finds annotations from a class using configurable traversal options. 512 * 513 * <p> 514 * This method provides a flexible API for traversing annotations. 515 * It uses {@link AnnotationTraversal} enums to configure what elements to search and in what order. 516 * 517 * <h5 class='section'>Examples:</h5> 518 * <p class='bjava'> 519 * <jc>// Search class only</jc> 520 * List<AnnotationInfo<MyAnnotation>> <jv>l1</jv> = 521 * find(MyAnnotation.<jk>class</jk>, <jv>ci</jv>, SELF); 522 * 523 * <jc>// Search class and parents</jc> 524 * List<AnnotationInfo<MyAnnotation>> <jv>l2</jv> = 525 * find(MyAnnotation.<jk>class</jk>, <jv>ci</jv>, SELF, PARENTS); 526 * 527 * <jc>// Search class, parents, and package (parent-first order using rstream)</jc> 528 * Stream<AnnotationInfo<MyAnnotation>> <jv>s3</jv> = 529 * rstream(find(MyAnnotation.<jk>class</jk>, <jv>ci</jv>, SELF, PARENTS, PACKAGE)); 530 * </p> 531 * 532 * @param <A> The annotation type. 533 * @param type The annotation type to search for. Must not be <jk>null</jk>. 534 * @param c The class to search. Must not be <jk>null</jk>. 535 * @param traversals The traversal options (what to search and order). 536 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 537 */ 538 public <A extends Annotation> List<AnnotationInfo<A>> find(Class<A> type, ClassInfo c, AnnotationTraversal...traversals) { 539 reqnn("type", type); 540 reqnn("c", c); 541 return cache.get(type, c, traversals); 542 } 543 544 /** 545 * Finds annotations from a constructor using configurable traversal options. 546 * 547 * <p> 548 * This method provides a flexible, stream-based API for traversing constructor annotations without creating intermediate lists. 549 * 550 * <h5 class='section'>Examples:</h5> 551 * <p class='bjava'> 552 * <jc>// Search constructor annotations</jc> 553 * Stream<AnnotationInfo<MyAnnotation>> <jv>s1</jv> = 554 * findAnnotations(MyAnnotation.<jk>class</jk>, <jv>ci</jv>, SELF); 555 * </p> 556 * 557 * @param <A> The annotation type. 558 * @param type The annotation type to search for. Must not be <jk>null</jk>. 559 * @param c The constructor to search. Must not be <jk>null</jk>. 560 * @param traversals The traversal options. 561 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 562 */ 563 public <A extends Annotation> List<AnnotationInfo<A>> find(Class<A> type, ConstructorInfo c, AnnotationTraversal...traversals) { 564 reqnn("type", type); 565 reqnn("c", c); 566 return cache.get(type, c, traversals); 567 } 568 569 /** 570 * Finds annotations from a field using configurable traversal options. 571 * 572 * <p> 573 * This method provides a flexible, stream-based API for traversing field annotations without creating intermediate lists. 574 * 575 * <h5 class='section'>Examples:</h5> 576 * <p class='bjava'> 577 * <jc>// Search field annotations</jc> 578 * Stream<AnnotationInfo<MyAnnotation>> <jv>s1</jv> = 579 * findAnnotations(MyAnnotation.<jk>class</jk>, <jv>fi</jv>, SELF); 580 * </p> 581 * 582 * @param <A> The annotation type. 583 * @param type The annotation type to search for. Must not be <jk>null</jk>. 584 * @param f The field to search. Must not be <jk>null</jk>. 585 * @param traversals The traversal options. 586 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 587 */ 588 public <A extends Annotation> List<AnnotationInfo<A>> find(Class<A> type, FieldInfo f, AnnotationTraversal...traversals) { 589 reqnn("type", type); 590 reqnn("f", f); 591 return cache.get(type, f, traversals); 592 } 593 594 /** 595 * Finds annotations from a method using configurable traversal options. 596 * 597 * <p> 598 * This method provides a flexible API for traversing method annotations. 599 * 600 * <h5 class='section'>Examples:</h5> 601 * <p class='bjava'> 602 * <jc>// Search method and matching parent methods</jc> 603 * List<AnnotationInfo<MyAnnotation>> <jv>l1</jv> = 604 * find(MyAnnotation.<jk>class</jk>, <jv>mi</jv>, SELF, MATCHING_METHODS); 605 * 606 * <jc>// Search method, matching methods, and return type (parent-first using rstream)</jc> 607 * Stream<AnnotationInfo<MyAnnotation>> <jv>s2</jv> = 608 * rstream(find(MyAnnotation.<jk>class</jk>, <jv>mi</jv>, SELF, MATCHING_METHODS, RETURN_TYPE)); 609 * </p> 610 * 611 * @param <A> The annotation type. 612 * @param type The annotation type to search for. Must not be <jk>null</jk>. 613 * @param m The method to search. Must not be <jk>null</jk>. 614 * @param traversals The traversal options. 615 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 616 */ 617 public <A extends Annotation> List<AnnotationInfo<A>> find(Class<A> type, MethodInfo m, AnnotationTraversal...traversals) { 618 reqnn("type", type); 619 reqnn("m", m); 620 return cache.get(type, m, traversals); 621 } 622 623 /** 624 * Finds annotations from a parameter using configurable traversal options in child-to-parent order. 625 * 626 * <p> 627 * This method provides a flexible, stream-based API for traversing parameter annotations without creating intermediate lists. 628 * 629 * <h5 class='section'>Supported Traversal Types:</h5> 630 * <ul> 631 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this parameter 632 * <li>{@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors (child-to-parent) 633 * <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - The parameter's type hierarchy (includes class parents and package) 634 * </ul> 635 * 636 * <p> 637 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE} 638 * 639 * <h5 class='section'>Examples:</h5> 640 * <p class='bjava'> 641 * <jc>// Search parameter, matching parameters, and parameter type (child-to-parent)</jc> 642 * Stream<AnnotationInfo<MyAnnotation>> <jv>s1</jv> = 643 * find(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF, MATCHING_PARAMETERS, PARAMETER_TYPE); 644 * 645 * <jc>// Just search this parameter</jc> 646 * Stream<AnnotationInfo<MyAnnotation>> <jv>s2</jv> = 647 * find(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF); 648 * 649 * <jc>// Search in parent-to-child order using findTopDown</jc> 650 * Stream<AnnotationInfo<MyAnnotation>> <jv>s3</jv> = 651 * findTopDown(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF, MATCHING_PARAMETERS, PARAMETER_TYPE); 652 * </p> 653 * 654 * @param <A> The annotation type. 655 * @param type The annotation type to search for. Must not be <jk>null</jk>. 656 * @param p The parameter to search. Must not be <jk>null</jk>. 657 * @param traversals 658 * The traversal options. If not specified, defaults to {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}. 659 * <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} 660 * @return A list of {@link AnnotationInfo} objects in child-to-parent order. Never <jk>null</jk>. 661 */ 662 public <A extends Annotation> List<AnnotationInfo<A>> find(Class<A> type, ParameterInfo p, AnnotationTraversal...traversals) { 663 reqnn("type", type); 664 reqnn("p", p); 665 return cache.get(type, p, traversals); 666 } 667 668 /** 669 * Finds all annotations from a class using configurable traversal options, without filtering by annotation type. 670 * 671 * <p> 672 * This method provides a flexible API for traversing all class annotations. 673 * Unlike {@link #find(Class, ClassInfo, AnnotationTraversal...)}, this method does not filter by annotation type. 674 * 675 * <h5 class='section'>Examples:</h5> 676 * <p class='bjava'> 677 * <jc>// Get all annotations from class only</jc> 678 * List<AnnotationInfo<Annotation>> <jv>l1</jv> = 679 * find(<jv>ci</jv>, SELF); 680 * 681 * <jc>// Get all annotations from class and parents</jc> 682 * List<AnnotationInfo<Annotation>> <jv>l2</jv> = 683 * find(<jv>ci</jv>, SELF, PARENTS); 684 * </p> 685 * 686 * @param c The class to search. Must not be <jk>null</jk>. 687 * @param traversals The traversal options (what to search and order). 688 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 689 */ 690 public List<AnnotationInfo<? extends Annotation>> find(ClassInfo c, AnnotationTraversal...traversals) { 691 reqnn("c", c); 692 return cache.get(null, c, traversals); 693 } 694 695 /** 696 * Finds all annotations from a constructor using configurable traversal options, without filtering by annotation type. 697 * 698 * <p> 699 * This method provides a flexible, stream-based API for traversing all constructor annotations without creating intermediate lists. 700 * Unlike {@link #find(Class, ConstructorInfo, AnnotationTraversal...)}, this method does not filter by annotation type. 701 * 702 * <h5 class='section'>Examples:</h5> 703 * <p class='bjava'> 704 * <jc>// Get all annotations from constructor</jc> 705 * Stream<AnnotationInfo<Annotation>> <jv>s1</jv> = 706 * find(<jv>ci</jv>, SELF); 707 * </p> 708 * 709 * @param c The constructor to search. Must not be <jk>null</jk>. 710 * @param traversals The traversal options. 711 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 712 */ 713 public List<AnnotationInfo<? extends Annotation>> find(ConstructorInfo c, AnnotationTraversal...traversals) { 714 reqnn("c", c); 715 return cache.get(null, c, traversals); 716 } 717 718 /** 719 * Finds all annotations from a field using configurable traversal options, without filtering by annotation type. 720 * 721 * <p> 722 * This method provides a flexible, stream-based API for traversing all field annotations without creating intermediate lists. 723 * Unlike {@link #find(Class, FieldInfo, AnnotationTraversal...)}, this method does not filter by annotation type. 724 * 725 * <h5 class='section'>Examples:</h5> 726 * <p class='bjava'> 727 * <jc>// Get all annotations from field</jc> 728 * Stream<AnnotationInfo<Annotation>> <jv>s1</jv> = 729 * find(<jv>fi</jv>, SELF); 730 * </p> 731 * 732 * @param f The field to search. Must not be <jk>null</jk>. 733 * @param traversals The traversal options. 734 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 735 */ 736 public List<AnnotationInfo<? extends Annotation>> find(FieldInfo f, AnnotationTraversal...traversals) { 737 reqnn("f", f); 738 return cache.get(null, f, traversals); 739 } 740 741 /** 742 * Finds all annotations from a method using configurable traversal options, without filtering by annotation type. 743 * 744 * <p> 745 * This method provides a flexible API for traversing all method annotations. 746 * Unlike {@link #find(Class, MethodInfo, AnnotationTraversal...)}, this method does not filter by annotation type. 747 * 748 * <h5 class='section'>Examples:</h5> 749 * <p class='bjava'> 750 * <jc>// Get all annotations from method and matching parent methods</jc> 751 * List<AnnotationInfo<Annotation>> <jv>l1</jv> = 752 * find(<jv>mi</jv>, SELF, MATCHING_METHODS); 753 * 754 * <jc>// Get all annotations from method, matching methods, and return type</jc> 755 * List<AnnotationInfo<Annotation>> <jv>l2</jv> = 756 * find(<jv>mi</jv>, SELF, MATCHING_METHODS, RETURN_TYPE); 757 * </p> 758 * 759 * @param m The method to search. Must not be <jk>null</jk>. 760 * @param traversals The traversal options. 761 * @return A list of {@link AnnotationInfo} objects. Never <jk>null</jk>. 762 */ 763 public List<AnnotationInfo<? extends Annotation>> find(MethodInfo m, AnnotationTraversal...traversals) { 764 reqnn("m", m); 765 return cache.get(null, m, traversals); 766 } 767 768 /** 769 * Finds all annotations from a parameter using configurable traversal options, without filtering by annotation type. 770 * 771 * <p> 772 * This method provides a flexible, stream-based API for traversing all parameter annotations without creating intermediate lists. 773 * Unlike {@link #find(Class, ParameterInfo, AnnotationTraversal...)}, this method does not filter by annotation type. 774 * 775 * <h5 class='section'>Supported Traversal Types:</h5> 776 * <ul> 777 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this parameter 778 * <li>{@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors (child-to-parent) 779 * <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - The parameter's type hierarchy (includes class parents and package) 780 * </ul> 781 * 782 * <p> 783 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE} 784 * 785 * <h5 class='section'>Examples:</h5> 786 * <p class='bjava'> 787 * <jc>// Get all annotations from parameter, matching parameters, and parameter type</jc> 788 * Stream<AnnotationInfo<Annotation>> <jv>s1</jv> = 789 * find(<jv>pi</jv>, SELF, MATCHING_PARAMETERS, PARAMETER_TYPE); 790 * 791 * <jc>// Just get annotations from this parameter</jc> 792 * Stream<AnnotationInfo<Annotation>> <jv>s2</jv> = 793 * find(<jv>pi</jv>, SELF); 794 * </p> 795 * 796 * @param p The parameter to search. Must not be <jk>null</jk>. 797 * @param traversals 798 * The traversal options. If not specified, defaults to {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}. 799 * <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} 800 * @return A list of {@link AnnotationInfo} objects in child-to-parent order. Never <jk>null</jk>. 801 */ 802 public List<AnnotationInfo<? extends Annotation>> find(ParameterInfo p, AnnotationTraversal...traversals) { 803 reqnn("p", p); 804 return cache.get(null, p, traversals); 805 } 806 807 /** 808 * Checks if a class has the specified annotation. 809 * 810 * <p> 811 * This is a convenience method equivalent to: 812 * <p class='bjava'> 813 * find(<jv>type</jv>, <jv>clazz</jv>, <jv>traversals</jv>).findFirst().isPresent() 814 * </p> 815 * 816 * <h5 class='section'>Supported Traversal Types:</h5> 817 * <ul> 818 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this class 819 * <li>{@link AnnotationTraversal#PARENTS PARENTS} - Parent classes and interfaces (child-to-parent order) 820 * <li>{@link AnnotationTraversal#PACKAGE PACKAGE} - The package annotations 821 * </ul> 822 * 823 * <p> 824 * <b>Default:</b> If no traversals are specified, defaults to: {@code PARENTS, PACKAGE} 825 * <br>Note: {@code PARENTS} includes the class itself plus all parent classes and interfaces. 826 * 827 * <h5 class='section'>Example:</h5> 828 * <p class='bjava'> 829 * <jc>// Check if class has @MyAnnotation anywhere in hierarchy</jc> 830 * <jk>boolean</jk> <jv>hasIt</jv> = has(MyAnnotation.<jk>class</jk>, <jv>ci</jv>); 831 * 832 * <jc>// Check only on the class itself</jc> 833 * <jk>boolean</jk> <jv>hasIt2</jv> = has(MyAnnotation.<jk>class</jk>, <jv>ci</jv>, SELF); 834 * </p> 835 * 836 * @param <A> The annotation type. 837 * @param type The annotation type to search for. Must not be <jk>null</jk>. 838 * @param c The class to search. Must not be <jk>null</jk>. 839 * @param traversals 840 * The traversal options. If not specified, defaults to {@code SELF, PARENTS, PACKAGE}. 841 * <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link AnnotationTraversal#PARENTS PARENTS}, {@link AnnotationTraversal#PACKAGE PACKAGE} 842 * @return <jk>true</jk> if the annotation is found, <jk>false</jk> otherwise. 843 */ 844 public <A extends Annotation> boolean has(Class<A> type, ClassInfo c, AnnotationTraversal...traversals) { 845 return ! find(type, c, traversals).isEmpty(); 846 } 847 848 /** 849 * Checks if a constructor has the specified annotation. 850 * 851 * <p> 852 * This is a convenience method equivalent to: 853 * <p class='bjava'> 854 * find(<jv>type</jv>, <jv>constructor</jv>, <jv>traversals</jv>).findFirst().isPresent() 855 * </p> 856 * 857 * <h5 class='section'>Supported Traversal Types:</h5> 858 * <ul> 859 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this constructor 860 * </ul> 861 * 862 * <p> 863 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF} 864 * 865 * <h5 class='section'>Example:</h5> 866 * <p class='bjava'> 867 * <jc>// Check if constructor has @MyAnnotation</jc> 868 * <jk>boolean</jk> <jv>hasIt</jv> = has(MyAnnotation.<jk>class</jk>, <jv>ci</jv>); 869 * </p> 870 * 871 * @param <A> The annotation type. 872 * @param type The annotation type to search for. Must not be <jk>null</jk>. 873 * @param c The constructor to search. Must not be <jk>null</jk>. 874 * @param traversals 875 * The traversal options. If not specified, defaults to {@code SELF}. 876 * <br>Valid values: {@link AnnotationTraversal#SELF SELF} 877 * @return <jk>true</jk> if the annotation is found, <jk>false</jk> otherwise. 878 */ 879 public <A extends Annotation> boolean has(Class<A> type, ConstructorInfo c, AnnotationTraversal...traversals) { 880 return ! find(type, c, traversals).isEmpty(); 881 } 882 883 /** 884 * Checks if a field has the specified annotation. 885 * 886 * <p> 887 * This is a convenience method equivalent to: 888 * <p class='bjava'> 889 * find(<jv>type</jv>, <jv>field</jv>, <jv>traversals</jv>).findFirst().isPresent() 890 * </p> 891 * 892 * <h5 class='section'>Supported Traversal Types:</h5> 893 * <ul> 894 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this field 895 * </ul> 896 * 897 * <p> 898 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF} 899 * 900 * <h5 class='section'>Example:</h5> 901 * <p class='bjava'> 902 * <jc>// Check if field has @MyAnnotation</jc> 903 * <jk>boolean</jk> <jv>hasIt</jv> = has(MyAnnotation.<jk>class</jk>, <jv>fi</jv>); 904 * </p> 905 * 906 * @param <A> The annotation type. 907 * @param type The annotation type to search for. Must not be <jk>null</jk>. 908 * @param f The field to search. Must not be <jk>null</jk>. 909 * @param traversals 910 * The traversal options. If not specified, defaults to {@code SELF}. 911 * <br>Valid values: {@link AnnotationTraversal#SELF SELF} 912 * @return <jk>true</jk> if the annotation is found, <jk>false</jk> otherwise. 913 */ 914 public <A extends Annotation> boolean has(Class<A> type, FieldInfo f, AnnotationTraversal...traversals) { 915 return ! find(type, f, traversals).isEmpty(); 916 } 917 918 /** 919 * Checks if a method has the specified annotation. 920 * 921 * <p> 922 * This is a convenience method equivalent to: 923 * <p class='bjava'> 924 * find(<jv>type</jv>, <jv>method</jv>, <jv>traversals</jv>).findFirst().isPresent() 925 * </p> 926 * 927 * <h5 class='section'>Supported Traversal Types:</h5> 928 * <ul> 929 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this method 930 * <li>{@link AnnotationTraversal#MATCHING_METHODS MATCHING_METHODS} - Matching methods in parent classes (child-to-parent) 931 * <li>{@link AnnotationTraversal#RETURN_TYPE RETURN_TYPE} - The return type hierarchy (includes class parents and package) 932 * <li>{@link AnnotationTraversal#PACKAGE PACKAGE} - The declaring class's package annotations 933 * </ul> 934 * 935 * <p> 936 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF, MATCHING_METHODS, RETURN_TYPE, PACKAGE} 937 * 938 * <h5 class='section'>Example:</h5> 939 * <p class='bjava'> 940 * <jc>// Check if method has @MyAnnotation anywhere in hierarchy</jc> 941 * <jk>boolean</jk> <jv>hasIt</jv> = has(MyAnnotation.<jk>class</jk>, <jv>mi</jv>); 942 * 943 * <jc>// Check only on the method itself</jc> 944 * <jk>boolean</jk> <jv>hasIt2</jv> = has(MyAnnotation.<jk>class</jk>, <jv>mi</jv>, SELF); 945 * </p> 946 * 947 * @param <A> The annotation type. 948 * @param type The annotation type to search for. Must not be <jk>null</jk>. 949 * @param m The method to search. Must not be <jk>null</jk>. 950 * @param traversals 951 * The traversal options. If not specified, defaults to {@code SELF, MATCHING_METHODS, RETURN_TYPE, PACKAGE}. 952 * <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link AnnotationTraversal#MATCHING_METHODS MATCHING_METHODS}, {@link AnnotationTraversal#RETURN_TYPE RETURN_TYPE}, {@link AnnotationTraversal#PACKAGE PACKAGE} 953 * @return <jk>true</jk> if the annotation is found, <jk>false</jk> otherwise. 954 */ 955 public <A extends Annotation> boolean has(Class<A> type, MethodInfo m, AnnotationTraversal...traversals) { 956 return ! find(type, m, traversals).isEmpty(); 957 } 958 959 /** 960 * Checks if a parameter has the specified annotation. 961 * 962 * <p> 963 * This is a convenience method equivalent to: 964 * <p class='bjava'> 965 * find(<jv>type</jv>, <jv>parameter</jv>, <jv>traversals</jv>).findFirst().isPresent() 966 * </p> 967 * 968 * <h5 class='section'>Supported Traversal Types:</h5> 969 * <ul> 970 * <li>{@link AnnotationTraversal#SELF SELF} - Annotations declared directly on this parameter 971 * <li>{@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors (child-to-parent) 972 * <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - The parameter's type hierarchy (includes class parents and package) 973 * </ul> 974 * 975 * <p> 976 * <b>Default:</b> If no traversals are specified, defaults to: {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE} 977 * 978 * <h5 class='section'>Example:</h5> 979 * <p class='bjava'> 980 * <jc>// Check if parameter has @MyAnnotation anywhere in hierarchy</jc> 981 * <jk>boolean</jk> <jv>hasIt</jv> = has(MyAnnotation.<jk>class</jk>, <jv>pi</jv>); 982 * 983 * <jc>// Check only on the parameter itself</jc> 984 * <jk>boolean</jk> <jv>hasIt2</jv> = has(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF); 985 * </p> 986 * 987 * @param <A> The annotation type. 988 * @param type The annotation type to search for. Must not be <jk>null</jk>. 989 * @param p The parameter to search. Must not be <jk>null</jk>. 990 * @param traversals 991 * The traversal options. If not specified, defaults to {@code SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}. 992 * <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} 993 * @return <jk>true</jk> if the annotation is found, <jk>false</jk> otherwise. 994 */ 995 public <A extends Annotation> boolean has(Class<A> type, ParameterInfo p, AnnotationTraversal...traversals) { 996 return ! find(type, p, traversals).isEmpty(); 997 } 998 999 /** 1000 * Computes and caches the complete list of annotations for a given type, class, and traversal combination. 1001 * This is the supplier function for the findCache. 1002 */ 1003 @SuppressWarnings({ 1004 "java:S6541" // Synchronization not needed for cache access pattern 1005 }) 1006 private List load(Class<?> type, ElementInfo element, AnnotationTraversal[] traversals) { 1007 1008 if (type != null) { 1009 return cache.get(null, element, traversals).stream().filter(x -> ((AnnotationInfo)x).isType(type)).toList(); 1010 } 1011 1012 var l = new ArrayList(); 1013 1014 List<AnnotationTraversal> t; 1015 if (traversals.length > 0) 1016 t = l(traversals); 1017 else if (element instanceof ClassInfo) 1018 t = l(a(PARENTS, PACKAGE)); 1019 else if (element instanceof MethodInfo) 1020 t = l(a(SELF, MATCHING_METHODS, DECLARING_CLASS, RETURN_TYPE, PACKAGE)); 1021 else if (element instanceof FieldInfo || element instanceof ConstructorInfo) 1022 t = l(a(SELF)); 1023 else { 1024 reqt(ParameterInfo.class, element, Shorts::uoex); 1025 t = l(a(SELF, MATCHING_PARAMETERS, PARAMETER_TYPE)); 1026 } 1027 1028 if (element instanceof ClassInfo element2) { 1029 if (t.contains(SELF)) { 1030 l.addAll(runtimeCache.get(element2.inner())); 1031 l.addAll(element2.getDeclaredAnnotations()); 1032 } 1033 if (t.contains(PARENTS)) { 1034 for (var p : element2.getParentsAndInterfaces()) { 1035 l.addAll(runtimeCache.get(p.inner())); 1036 l.addAll(p.getDeclaredAnnotations()); 1037 } 1038 } 1039 if (t.contains(PACKAGE) && element2.getPackage() != null) 1040 l.addAll(element2.getPackage().getAnnotations()); 1041 } else if (element instanceof MethodInfo element2) { 1042 if (t.contains(SELF)) { 1043 l.addAll(runtimeCache.get(element2.inner())); 1044 l.addAll(element2.getDeclaredAnnotations()); 1045 } 1046 if (t.contains(MATCHING_METHODS)) { 1047 for (var m : element2.getMatchingMethods().stream().skip(1).toList()) { 1048 l.addAll(runtimeCache.get(m.inner())); 1049 l.addAll(m.getDeclaredAnnotations()); 1050 } 1051 } 1052 if (t.contains(DECLARING_CLASS)) { 1053 l.addAll(find(element2.getDeclaringClass(), a(PARENTS))); 1054 } 1055 if (t.contains(RETURN_TYPE)) { 1056 l.addAll(find(element2.getReturnType().unwrap(Holder.class, Optional.class), a(PARENTS))); 1057 } 1058 if (t.contains(PACKAGE) && element2.getDeclaringClass().getPackage() != null) 1059 l.addAll(element2.getDeclaringClass().getPackage().getAnnotations()); 1060 } else if (element instanceof FieldInfo element2) { 1061 if (t.contains(SELF)) { 1062 l.addAll(runtimeCache.get(element2.inner())); 1063 l.addAll(element2.getAnnotations()); 1064 } 1065 } else if (element instanceof ConstructorInfo element2) { 1066 if (t.contains(SELF)) { 1067 l.addAll(runtimeCache.get(element2.inner())); 1068 l.addAll(element2.getDeclaredAnnotations()); 1069 } 1070 } else if (element instanceof ParameterInfo element2) { 1071 if (t.contains(SELF)) { 1072 l.addAll(element2.getAnnotations()); 1073 } 1074 if (t.contains(MATCHING_PARAMETERS)) { 1075 for (var p : element2.getMatchingParameters().stream().skip(1).toList()) { 1076 l.addAll(p.getAnnotations()); 1077 } 1078 } 1079 if (t.contains(PARAMETER_TYPE)) { 1080 l.addAll(find(element2.getParameterType().unwrap(Holder.class, Optional.class), a(PARENTS, PACKAGE))); 1081 } 1082 } 1083 1084 return l; 1085 } 1086 1087 private List load(Object o) { 1088 if (o instanceof Class o2) { 1089 var ci = ClassInfo.of(o2); 1090 return annotationMap == null ? emptyList() : annotationMap.find(ci.inner()).map(a -> ai(ci, a)).toList(); 1091 } 1092 if (o instanceof Method o2) { 1093 var mi = info(o2); 1094 return annotationMap == null ? emptyList() : annotationMap.find(mi.inner()).map(a -> ai(mi, a)).toList(); 1095 } 1096 if (o instanceof Field o2) { 1097 var fi = info(o2); 1098 return annotationMap == null ? emptyList() : annotationMap.find(fi.inner()).map(a -> ai(fi, a)).toList(); 1099 } 1100 if (o instanceof Constructor o2) { 1101 var ci = info(o2); 1102 return annotationMap == null ? emptyList() : annotationMap.find(ci.inner()).map(a -> ai(ci, a)).toList(); 1103 } 1104 throw uoex(); 1105 } 1106}