001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2026 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.construct.element; 015 016import java.lang.annotation.ElementType; 017import java.lang.annotation.RetentionPolicy; 018 019import java.util.ArrayDeque; 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.EnumSet; 023import java.util.Iterator; 024import java.util.LinkedList; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028import java.util.Objects; 029import java.util.Queue; 030import java.util.SequencedMap; 031import java.util.Set; 032 033import java.util.function.Predicate; 034 035import java.util.stream.Stream; 036 037import javax.lang.model.AnnotatedConstruct; 038 039import javax.lang.model.element.AnnotationMirror; 040import javax.lang.model.element.AnnotationValue; 041import javax.lang.model.element.Element; 042import javax.lang.model.element.ExecutableElement; 043import javax.lang.model.element.Name; 044import javax.lang.model.element.QualifiedNameable; 045import javax.lang.model.element.TypeElement; 046import javax.lang.model.element.VariableElement; 047 048import javax.lang.model.type.ArrayType; 049import javax.lang.model.type.DeclaredType; 050import javax.lang.model.type.PrimitiveType; 051import javax.lang.model.type.TypeMirror; 052 053import static java.util.Collections.unmodifiableList; 054import static java.util.Collections.unmodifiableSequencedMap; 055import static java.util.Collections.unmodifiableSet; 056 057import static java.util.LinkedHashMap.newLinkedHashMap; 058 059import static java.util.HashSet.newHashSet; 060 061import static java.util.function.Function.identity; 062 063import static java.util.stream.Stream.concat; 064import static java.util.stream.Stream.empty; 065import static java.util.stream.Stream.iterate; 066 067import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE; 068import static javax.lang.model.element.ElementKind.CLASS; 069import static javax.lang.model.element.ElementKind.METHOD; 070 071import static javax.lang.model.element.Modifier.ABSTRACT; 072import static javax.lang.model.element.Modifier.PUBLIC; 073 074import static javax.lang.model.type.TypeKind.ARRAY; 075import static javax.lang.model.type.TypeKind.DECLARED; 076 077import static javax.lang.model.util.ElementFilter.methodsIn; 078 079/** 080 * A utility class for working with annotations as represented by {@link AnnotationMirror}s, {@link ExecutableElement}s, 081 * and {@link AnnotationValue}s. 082 * 083 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 084 */ 085public final class AnnotationMirrors { 086 087 private static final Set<ElementType> EMPTY_ELEMENT_TYPES = unmodifiableSet(EnumSet.noneOf(ElementType.class)); 088 089 private static final SequencedMap<?, ?> EMPTY_MAP = unmodifiableSequencedMap(newLinkedHashMap(0)); 090 091 private AnnotationMirrors() { 092 super(); 093 } 094 095 /** 096 * Returns a determinate, non-{@code null}, immutable {@link List} of {@link AnnotationMirror}s <dfn>present</dfn> on 097 * the supplied {@link Element}. 098 * 099 * <p>This method is a more capable, better-typed replacement of the {@link 100 * javax.lang.model.util.Elements#getAllAnnotationMirrors(Element)} method, and should be preferred.</p> 101 * 102 * @param e an {@link Element}; must not be {@code null} 103 * 104 * @return a determinate, non-{@code null}, immutable {@link List} of {@link AnnotationMirror}s <dfn>present</dfn> on 105 * the supplied {@link Element} 106 * 107 * @exception NullPointerException if {@code e} is {@code null} 108 * 109 * @see javax.lang.model.util.Elements#getAllAnnotationMirrors(Element) 110 */ 111 public static final List<? extends AnnotationMirror> allAnnotationMirrors(Element e) { 112 final List<AnnotationMirror> allAnnotations = new LinkedList<>(e.getAnnotationMirrors()); 113 WHILE_LOOP: 114 while (e.getKind() == CLASS && e instanceof TypeElement te) { 115 final TypeMirror sct = te.getSuperclass(); 116 if (sct.getKind() != DECLARED || !(sct instanceof DeclaredType)) { 117 break; 118 } 119 e = ((DeclaredType)sct).asElement(); 120 final List<? extends AnnotationMirror> superclassAnnotations = e.getAnnotationMirrors(); 121 if (!superclassAnnotations.isEmpty()) { 122 int added = 0; 123 for (final AnnotationMirror superclassAnnotation : superclassAnnotations) { 124 if (inherited(superclassAnnotation)) { 125 for (final AnnotationMirror a : allAnnotations.subList(added, allAnnotations.size())) { 126 if (((QualifiedNameable)superclassAnnotation.getAnnotationType().asElement()).getQualifiedName().contentEquals(((QualifiedNameable)a.getAnnotationType().asElement()).getQualifiedName())) { 127 continue WHILE_LOOP; 128 } 129 } 130 // javac prepends superclass annotations, resulting in a strage order; we duplicate it 131 allAnnotations.addFirst(superclassAnnotation); 132 ++added; 133 } 134 } 135 } 136 } 137 return allAnnotations.isEmpty() ? List.of() : unmodifiableList(allAnnotations); 138 } 139 140 /** 141 * For the supplied {@link AnnotationMirror}, returns an immutable, determinate {@link SequencedMap} of {@link 142 * AnnotationValue} instances indexed by the {@link ExecutableElement}s to which they apply. 143 * 144 * <p>Each {@link ExecutableElement} represents an <a 145 * href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1">annotation interface element</a> and 146 * meets the requirements of such an element.</p> 147 * 148 * <p>Each {@link AnnotationValue} represents the value of an annotation interface element and meets the requirements 149 * of such a value.</p> 150 * 151 * <p>This method is a more capable, better-typed replacement of the {@link 152 * javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror)} method, and should be preferred.</p> 153 * 154 * @param a an {@link AnnotationMirror}; may be {@code null} in which case an empty, immutable, determinate {@link 155 * SequencedMap} will be returned 156 * 157 * @return an immutable, determinate {@link Map} of {@link AnnotationValue} instances indexed by {@link 158 * ExecutableElement}s 159 * 160 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1 Java Language Specification, section 161 * 9.6.1 162 * 163 * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror) 164 */ 165 public static final SequencedMap<ExecutableElement, AnnotationValue> allAnnotationValues(final AnnotationMirror a) { 166 if (a == null) { 167 return emptySequencedMap(); 168 } 169 final Collection<? extends ExecutableElement> elements = methodsIn(a.getAnnotationType().asElement().getEnclosedElements()); 170 if (elements.isEmpty()) { 171 return emptySequencedMap(); 172 } 173 final SequencedMap<ExecutableElement, AnnotationValue> m = newLinkedHashMap(elements.size()); 174 final Map<? extends ExecutableElement, ? extends AnnotationValue> explicitValues = a.getElementValues(); 175 for (final ExecutableElement ee : elements) { 176 // You're going to want to use getOrDefault() here. Go ahead and try but you'll run into typing issues. 177 m.put(ee, explicitValues.containsKey(ee) ? explicitValues.get(ee) : ee.getDefaultValue()); 178 } 179 return m.isEmpty() ? emptySequencedMap() : unmodifiableSequencedMap(m); 180 } 181 182 /** 183 * Returns {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link 184 * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as 185 * the supplied {@link AnnotationMirror}. 186 * 187 * @param c a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 188 * 189 * @param a a non-{@code null} {@link AnnotationMirror} 190 * 191 * @return {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link 192 * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as 193 * the supplied {@link AnnotationMirror} 194 * 195 * @exception NullPointerException if {@code c} or {@code a} is {@code null} 196 * 197 * @see #contains(collection, AnnotationMirror, Predicate) 198 */ 199 public static final boolean contains(final Collection<? extends AnnotationMirror> c, 200 final AnnotationMirror a) { 201 return contains(c, a, null); 202 } 203 204 /** 205 * Returns {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link 206 * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as 207 * the supplied {@link AnnotationMirror}. 208 * 209 * @param c a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 210 * 211 * @param a a non-{@code null} {@link AnnotationMirror} 212 * 213 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 214 * annotation element, is to be included in comparison operations; may be {@code null} in which case it is as if 215 * {@code e -> true} were supplied instead 216 * 217 * @return {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link 218 * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as 219 * the supplied {@link AnnotationMirror} 220 * 221 * @exception NullPointerException if {@code c} or {@code a} is {@code null} 222 * 223 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) 224 * 225 * @see #containsAll(collection, Collection, Predicate) 226 */ 227 public static final boolean contains(final Collection<? extends AnnotationMirror> c, 228 final AnnotationMirror a, 229 final Predicate<? super ExecutableElement> p) { 230 for (final AnnotationMirror ca : c) { 231 if (sameAnnotation(ca, a, p)) { 232 return true; 233 } 234 } 235 return false; 236 } 237 238 /** 239 * Returns {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, 240 * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1}, 241 * 242 * @param c0 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 243 * 244 * @param c1 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 245 * 246 * @return {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, 247 * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1} 248 * 249 * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} 250 * 251 * @see #containsAll(Collection, Collection, Predicate) 252 */ 253 public static final boolean containsAll(final Collection<? extends AnnotationMirror> c0, 254 final Collection<? extends AnnotationMirror> c1) { 255 return containsAll(c0, c1, null); 256 } 257 258 /** 259 * Returns {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, 260 * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1}, 261 * 262 * @param c0 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 263 * 264 * @param c1 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 265 * 266 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 267 * annotation element, is to be included in comparison operations; may be {@code null} in which case it is as if 268 * {@code e -> true} were supplied instead 269 * 270 * @return {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, 271 * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1} 272 * 273 * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} 274 * 275 * @see #contains(Collection, AnnotationMirror, Predicate) 276 * 277 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) 278 */ 279 public static final boolean containsAll(final Collection<? extends AnnotationMirror> c0, 280 final Collection<? extends AnnotationMirror> c1, 281 final Predicate<? super ExecutableElement> p) { 282 if (c0.size() < c1.size()) { 283 return false; 284 } 285 for (final AnnotationMirror a1 : c1) { 286 if (!contains(c0, a1, p)) { 287 return false; 288 } 289 } 290 return true; 291 } 292 293 /** 294 * Returns the (determinate) {@link AnnotationMirror} <em>directly present</em> on the supplied {@link 295 * AnnotatedConstruct} whose {@linkplain AnnotationMirror#getAnnotationType() annotation type}'s {@link 296 * javax.lang.model.type.DeclaredType#asElement() TypeElement} {@linkplain TypeElement#getQualifiedName() bears} the 297 * supplied {@code fullyQualifiedName}, or {@code null} if no such {@link AnnotationMirror} exists. 298 * 299 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 300 * 301 * @param name a {@link CharSequence}; may be {@code null} in which case {@code null} will be returned 302 * 303 * @return an {@link AnnotationMirror}, or {@code null} 304 * 305 * @exception NullPointerException if {@code ac} is {@code null} 306 * 307 * @see #streamBreadthFirst(AnnotatedConstruct) 308 * 309 * @see #streamDepthFirst(AnnotatedConstruct) 310 * 311 * @see AnnotationMirror#getAnnotationType() 312 * 313 * @see javax.lang.model.type.DeclaredType#asElement() 314 * 315 * @see TypeElement#getQualifiedName() 316 * 317 * @see javax.lang.model.element.Name#contentEquals(CharSequence) 318 */ 319 public static final AnnotationMirror get(final AnnotatedConstruct ac, final CharSequence name) { 320 if (name == null) { 321 return null; 322 } 323 for (final AnnotationMirror am : ac.getAnnotationMirrors()) { 324 final TypeElement e = (TypeElement)am.getAnnotationType().asElement(); 325 if (e.getQualifiedName().contentEquals(name)) { 326 return am; 327 } 328 } 329 return null; 330 } 331 332 /** 333 * A convenience method that returns a value for an annotation interface element {@linkplain 334 * ExecutableElement#getSimpleName() named} by the supplied {@link CharSequence} and logically owned by the supplied 335 * {@link AnnotationMirror}, or {@code null} if no such value exists. 336 * 337 * @param am an {@link AnnotationMirror}; must not be {@code null} 338 * 339 * @param name a {@link CharSequence}; may be {@code null} in which case {@code null} will be returned 340 * 341 * @return the result of invoking {@link AnnotationValue#getValue() getValue()} on an {@link AnnotationValue}, or 342 * {@code null} 343 * 344 * @exception NullPointerException if {@code am} is {@code null} 345 * 346 * @see AnnotationValue 347 * 348 * @see #allAnnotationValues(AnnotationMirror) 349 * 350 * @see #get(Map, CharSequence) 351 */ 352 public static final Object get(final AnnotationMirror am, final CharSequence name) { 353 return name == null ? null : get(allAnnotationValues(am), name); 354 } 355 356 /** 357 * A convenience method that returns a value for an annotation interface element {@linkplain 358 * ExecutableElement#getSimpleName() named} by the supplied {@link CharSequence} and found in the supplied {@link 359 * Map}, or {@code null} if no such value exists. 360 * 361 * @param values a {@link Map} as returned by the {@link #allAnnotationValues(AnnotationMirror)} method; must not be 362 * {@code null} 363 * 364 * @param name a {@link CharSequence}; may be {@code null} in which case {@code null} will be returned 365 * 366 * @return the result of invoking {@link AnnotationValue#getValue() getValue()} on a suitable {@link AnnotationValue} 367 * found in the supplied {@link Map}, or {@code null} 368 * 369 * @exception NullPointerException if {@code values} is {@code null} 370 * 371 * @see AnnotationValue 372 * 373 * @see #allAnnotationValues(AnnotationMirror) 374 */ 375 public static final Object get(final Map<? extends ExecutableElement, ? extends AnnotationValue> values, 376 final CharSequence name) { 377 if (name == null) { 378 return null; 379 } 380 for (final Entry<? extends Element, ? extends AnnotationValue> e : values.entrySet()) { 381 if (e.getKey().getSimpleName().contentEquals(name)) { 382 final AnnotationValue av = e.getValue(); 383 return av == null ? null : av.getValue(); 384 } 385 } 386 return null; 387 } 388 389 /** 390 * An <strong>experimental</strong> method that returns a hashcode for an {@link AnnotationMirror} according as much 391 * as possible to the rules described in the {@link java.lang.annotation.Annotation#hashCode()} contract. 392 * 393 * @param a an {@link AnnotationMirror} for which a hashcode should be computed; may be {@code null} in which case 394 * {@code 0} will be returned 395 * 396 * @return a hashcode for the supplied {@link AnnotationMirror} computed according to the rules described in the 397 * {@link java.lang.annotation.Annotation#hashCode()} contract 398 * 399 * @see #hashCode(AnnotationMirror, Predicate) 400 * 401 * @see java.lang.annotation.Annotation#hashCode() 402 */ 403 public static final int hashCode(final AnnotationMirror a) { 404 return hashCode(a, null); 405 } 406 407 /** 408 * An <strong>experimental</strong> method that returns a hashcode for an {@link AnnotationMirror} according as much 409 * as possible to the rules described in the {@link java.lang.annotation.Annotation#hashCode()} contract. 410 * 411 * @param a an {@link AnnotationMirror} for which a hashcode should be computed; may be {@code null} in which case 412 * {@code 0} will be returned 413 * 414 * @param p a {@link Predicate} that accepts a (non-{@code null}) {@link ExecutableElement} representing an annotation 415 * element and returns {@code true} if and only if the element should be included; may be {@code null} in which case a 416 * {@link Predicate} semantically identical to {@code ee -> true} will be used instead 417 * 418 * @return a hashcode for the supplied {@link AnnotationMirror} computed according to the rules described in the 419 * {@link java.lang.annotation.Annotation#hashCode()} contract 420 * 421 * @see java.lang.annotation.Annotation#hashCode() 422 */ 423 public static final int hashCode(final AnnotationMirror a, final Predicate<? super ExecutableElement> p) { 424 return a == null ? 0 : new AnnotationValueHashcodeVisitor().visitAnnotation(a, p == null ? ee -> true : p).intValue(); 425 } 426 427 /** 428 * Returns {@code true} if and only if the supplied {@link AnnotationMirror}'s {@linkplain 429 * AnnotationMirror#getAnnotationType() annotation type} is {@linkplain javax.lang.model.type.DeclaredType#asElement() 430 * declared by} an element that has been (meta-) {@linkplain Element#getAnnotationMirrors() annotated} with {@link 431 * java.lang.annotation.Inherited}. 432 * 433 * @param a an {@link AnnotationMirror}; must not be {@code null} 434 * 435 * @return {@code true} if and only if the supplied {@link AnnotationMirror}'s {@linkplain 436 * AnnotationMirror#getAnnotationType() annotation type} is {@linkplain javax.lang.model.type.DeclaredType#asElement() 437 * declared by} an element that has been (meta-) {@linkplain Element#getAnnotationMirrors() annotated} with {@link 438 * java.lang.annotation.Inherited} 439 * 440 * @exception NullPointerException if {@code a} is {@code null} 441 * 442 * @see #inherited(TypeElement) 443 */ 444 public static final boolean inherited(final AnnotationMirror a) { 445 return inherited((TypeElement)a.getAnnotationType().asElement()); 446 } 447 448 /** 449 * Returns {@code true} if and only if the supplied {@link TypeElement} represents an {@linkplain 450 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface} and if it has been (meta-) annotated 451 * with {@link java.lang.annotation.Inherited}. 452 * 453 * @param annotationInterface a {@link TypeElement} representing an {@linkplain 454 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface}; must not be {@code null} 455 * 456 * @return {@code true} if and only if the supplied {@link TypeElement} represents an {@linkplain 457 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface} and if it has been (meta-) annotated 458 * with {@link java.lang.annotation.Inherited} 459 * 460 * @exception NullPointerException if {@code annotationInterface} is {@code null} 461 * 462 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.4.3 Java Language Specification, 463 * section 9.6.4.3 464 */ 465 public static final boolean inherited(final TypeElement annotationInterface) { 466 if (annotationInterface.getKind() == ANNOTATION_TYPE) { 467 for (final AnnotationMirror ma : annotationInterface.getAnnotationMirrors()) { 468 if (((QualifiedNameable)ma.getAnnotationType().asElement()).getQualifiedName().contentEquals("java.lang.annotation.Inherited")) { 469 return true; 470 } 471 } 472 } 473 return false; 474 } 475 476 /** 477 * Returns a {@link RetentionPolicy} for the supplied {@link AnnotationMirror}, or {@link RetentionPolicy#CLASS} if, 478 * for any reason, a retention policy cannot be found or computed. 479 * 480 * @param a an {@link AnnotationMirror}; must not be {@code null} 481 * 482 * @return the {@link RetentionPolicy} for the supplied {@link AnnotationMirror}; never {@code null} 483 * 484 * @exception NullPointerException if {@code a} is {@code null} 485 * 486 * @see #retentionPolicy(TypeElement) 487 */ 488 public static final RetentionPolicy retentionPolicy(final AnnotationMirror a) { 489 return retentionPolicy((TypeElement)a.getAnnotationType().asElement()); 490 } 491 492 /** 493 * Returns a {@link RetentionPolicy} for the supplied {@link TypeElement} representing an {@linkplain 494 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface}, or {@link RetentionPolicy#CLASS} if, 495 * for any reason, a retention policy cannot be found or computed. 496 * 497 * @param annotationInterface a {@link TypeElement}; must be non-{@code null} and should represent an {@linkplain 498 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface} 499 * 500 * @return the {@link RetentionPolicy} for the supplied {@link TypeElement}; never {@code null} 501 * 502 * @exception NullPointerException if {@code annotationInterface} is {@code null} 503 * 504 * @see RetentionPolicy 505 * 506 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.4.2 Java Language Specification, 507 * section 9.6.4.2 508 */ 509 public static final RetentionPolicy retentionPolicy(final TypeElement annotationInterface) { 510 if (annotationInterface.getKind() == ANNOTATION_TYPE) { 511 for (final AnnotationMirror ma : annotationInterface.getAnnotationMirrors()) { 512 if (((QualifiedNameable)ma.getAnnotationType().asElement()).getQualifiedName().contentEquals("java.lang.annotation.Retention")) { 513 return RetentionPolicy.valueOf(((VariableElement)get(ma, "value")).getSimpleName().toString()); 514 } 515 } 516 } 517 return RetentionPolicy.CLASS; 518 } 519 520 /** 521 * Determines whether the two {@link AnnotationMirror}s represent the same (otherwise opaque) annotation. 522 * 523 * @param am0 an {@link AnnotationMirror}; may be {@code null} 524 * 525 * @param am1 an {@link AnnotationMirror}; may be {@code null} 526 * 527 * @return {@code true} if the supplied {@link AnnotationMirror}s represent the same (otherwise opaque) annotation; 528 * {@code false} otherwise 529 * 530 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) 531 */ 532 public static final boolean sameAnnotation(final AnnotationMirror am0, final AnnotationMirror am1) { 533 return sameAnnotation(am0, am1, null); 534 } 535 536 /** 537 * Determines whether the two {@link AnnotationMirror}s represent the same (underlying, otherwise opaque) annotation. 538 * 539 * @param am0 an {@link AnnotationMirror}; may be {@code null} 540 * 541 * @param am1 an {@link AnnotationMirror}; may be {@code null} 542 * 543 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 544 * annotation interface element, is to be included in the computation; may be {@code null} in which case it is as if 545 * {@code e -> true} were supplied instead 546 * 547 * @return {@code true} if the supplied {@link AnnotationMirror}s represent the same (underlying, otherwise opaque) 548 * annotation; {@code false} otherwise 549 * 550 * @see SameAnnotationValueVisitor 551 * 552 * @see SameAnnotationValueVisitor#visitAnnotation(AnnotationMirror, Object) 553 * 554 * @see #allAnnotationValues(AnnotationMirror) 555 */ 556 public static final boolean sameAnnotation(final AnnotationMirror am0, 557 final AnnotationMirror am1, 558 final Predicate<? super ExecutableElement> p) { 559 return am0 == am1 || new SameAnnotationValueVisitor(p).visitAnnotation(am0, am1); 560 } 561 562 /** 563 * Returns {@code true} if {@code c0} has all the {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, 564 * Predicate) same annotations} as {@code c1}, and if {@code c1} has all the {@linkplain 565 * #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) same annotations} as {@code c0}. 566 * 567 * @param c0 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 568 * 569 * @param c1 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 570 * 571 * @return {@code true} if {@code c0} has all the {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, 572 * Predicate) same annotations} as {@code c1}, and if {@code c1} has all the {@linkplain 573 * #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) same annotations} as {@code c0} 574 * 575 * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} 576 * 577 * @see #sameAnnotations(Collection, Collection, Predicate) 578 */ 579 public static final boolean sameAnnotations(final Collection<? extends AnnotationMirror> c0, 580 final Collection<? extends AnnotationMirror> c1) { 581 return sameAnnotations(c0, c1, null); 582 } 583 584 /** 585 * Returns {@code true} if {@code c0} has all the {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, 586 * Predicate) same annotations} as {@code c1}, and if {@code c1} has all the {@linkplain 587 * #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) same annotations} as {@code c0}. 588 * 589 * @param c0 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 590 * 591 * @param c1 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 592 * 593 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 594 * annotation interface element, is to be included in the computation; may be {@code null} in which case it is as if 595 * {@code e -> true} were supplied instead 596 * 597 * @return {@code true} if {@code c0} has all the {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, 598 * Predicate) same annotations} as {@code c1}, and if {@code c1} has all the {@linkplain 599 * #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) same annotations} as {@code c0} 600 * 601 * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} 602 * 603 * @see #containsAll(Collection, Collection, Predicate) 604 * 605 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) 606 */ 607 public static final boolean sameAnnotations(final Collection<? extends AnnotationMirror> c0, 608 final Collection<? extends AnnotationMirror> c1, 609 final Predicate<? super ExecutableElement> p) { 610 return c0.size() == c1.size() && containsAll(c0, c1, p) && containsAll(c1, c0, p); 611 } 612 613 /** 614 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotatedConstruct}'s 615 * {@linkplain AnnotatedConstruct#getAnnotationMirrors() annotations}, and their (meta-) annotations, in breadth-first 616 * order. 617 * 618 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror)} 619 * method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 620 * 621 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 622 * 623 * @return a non-{@code null} {@link Stream} of {@link AnnotationMirror}s 624 * 625 * @exception NullPointerException if {@code ac} is {@code null} 626 * 627 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 628 */ 629 public static final Stream<AnnotationMirror> streamBreadthFirst(final AnnotatedConstruct ac) { 630 return streamBreadthFirst(ac, AnnotationMirrors::returnTrue); 631 } 632 633 /** 634 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotatedConstruct}'s 635 * {@linkplain AnnotatedConstruct#getAnnotationMirrors() annotations}, and their (meta-) annotations, in breadth-first 636 * order. 637 * 638 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror, 639 * Predicate)} method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 640 * 641 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 642 * 643 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 644 * annotation interface element, is to be included in comparison operations; may be {@code null} in which case it is 645 * as if {@code e -> true} were supplied instead 646 * 647 * @return a non-{@code null} {@link Stream} of {@link AnnotationMirror}s 648 * 649 * @exception NullPointerException if {@code ac} is {@code null} 650 * 651 * @see #streamBreadthFirst(Collection, Predicate) 652 * 653 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 654 */ 655 public static final Stream<AnnotationMirror> streamBreadthFirst(final AnnotatedConstruct ac, 656 final Predicate<? super ExecutableElement> p) { 657 return streamBreadthFirst(ac.getAnnotationMirrors(), p); 658 } 659 660 /** 661 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotationMirror}s, and 662 * their (meta-) annotations, in breadth-first order. 663 * 664 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror)} 665 * method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 666 * 667 * @param ams a {@link Collection} of {@link AnnotationMirror}s; must not be {@code null} 668 * 669 * @return a non-{@code null} {@link Stream} of (distinct) {@link AnnotationMirror}s 670 * 671 * @exception NullPointerException if {@code ams} is {@code null} 672 * 673 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 674 */ 675 public static final Stream<AnnotationMirror> streamBreadthFirst(final Collection<? extends AnnotationMirror> ams) { 676 return streamBreadthFirst(ams, AnnotationMirrors::returnTrue); 677 } 678 679 /** 680 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotationMirror}s, and 681 * their (meta-) annotations, in breadth-first order. 682 * 683 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror, 684 * Predicate)} method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 685 * 686 * @param ams a {@link Collection} of {@link AnnotationMirror}s; must not be {@code null} 687 * 688 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 689 * annotation element, is to be included in comparison operations; may be {@code null} in which case it is as if 690 * {@code e -> true} were supplied instead 691 * 692 * @return a non-{@code null} {@link Stream} of (distinct) {@link AnnotationMirror}s 693 * 694 * @exception NullPointerException if {@code ams} is {@code null} 695 * 696 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) 697 */ 698 public static final Stream<AnnotationMirror> streamBreadthFirst(final Collection<? extends AnnotationMirror> ams, 699 final Predicate<? super ExecutableElement> p) { 700 if (ams.isEmpty()) { 701 return empty(); 702 } 703 final Collection<AnnotationMirror> seen = new ArrayList<>(); 704 final Queue<AnnotationMirror> q = new ArrayDeque<>(); 705 DEDUP_LOOP_0: 706 for (final AnnotationMirror a0 : ams) { 707 for (final AnnotationMirror a1 : seen) { 708 if (sameAnnotation(a0, a1, p)) { 709 continue DEDUP_LOOP_0; 710 } 711 } 712 q.add(a0); 713 seen.add(a0); 714 } 715 return 716 iterate(q.poll(), 717 Objects::nonNull, 718 a0 -> { 719 DEDUP_LOOP_1: 720 for (final AnnotationMirror a1 : a0.getAnnotationType().asElement().getAnnotationMirrors()) { 721 for (final AnnotationMirror a2 : seen) { 722 if (sameAnnotation(a1, a2, p)) { 723 continue DEDUP_LOOP_1; 724 } 725 } 726 q.add(a1); 727 seen.add(a1); 728 } 729 return q.poll(); 730 }); 731 } 732 733 /** 734 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotatedConstruct}'s 735 * {@linkplain AnnotatedConstruct#getAnnotationMirrors() annotations}, and their (meta-) annotations, in depth-first 736 * order. 737 * 738 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror)} 739 * method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 740 * 741 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 742 * 743 * @return a non-{@code null} {@link Stream} of {@link AnnotationMirror}s 744 * 745 * @exception NullPointerException if {@code ac} is {@code null} 746 * 747 * @see #streamDepthFirst(AnnotatedConstruct, Predicate) 748 * 749 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 750 */ 751 public static final Stream<AnnotationMirror> streamDepthFirst(final AnnotatedConstruct ac) { 752 return streamDepthFirst(ac, AnnotationMirrors::returnTrue); // 17 == arbitrary 753 } 754 755 /** 756 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotatedConstruct}'s 757 * {@linkplain AnnotatedConstruct#getAnnotationMirrors() annotations}, and their (meta-) annotations, in depth-first 758 * order. 759 * 760 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror, 761 * Predicate)} method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 762 * 763 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 764 * 765 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 766 * annotation element, is to be included in comparison operations; may be {@code null} in which case it is as if 767 * {@code e -> true} were supplied instead 768 * 769 * @return a non-{@code null}, sequential {@link Stream} of {@link AnnotationMirror}s 770 * 771 * @exception NullPointerException if {@code ac} is {@code null} 772 * 773 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 774 */ 775 public static final Stream<AnnotationMirror> streamDepthFirst(final AnnotatedConstruct ac, 776 final Predicate<? super ExecutableElement> p) { 777 return streamDepthFirst(ac, new ArrayList<>(17), p); // 17 == arbitrary 778 } 779 780 /** 781 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotationMirror}s, and 782 * their (meta-) annotations, in depth-first order. 783 * 784 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror)} 785 * method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 786 * 787 * @param ams a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 788 * 789 * @return a non-{@code null}, seqwuential {@link Stream} of {@link AnnotationMirror}s 790 * 791 * @exception NullPointerException if {@code ams} is {@code null} 792 * 793 * @see #streamDepthFirst(Collection, Predicate) 794 * 795 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 796 */ 797 public static final Stream<AnnotationMirror> streamDepthFirst(final Collection<? extends AnnotationMirror> ams) { 798 return streamDepthFirst(ams, AnnotationMirrors::returnTrue); // 17 == arbitrary 799 } 800 801 /** 802 * Returns a non-{@code null}, sequential {@link Stream} that traverses the supplied {@link AnnotationMirror}s, and 803 * their (meta-) annotations, in depth-first order. 804 * 805 * <p>Cycles and duplicates are avoided via usage of the {@link #sameAnnotation(AnnotationMirror, AnnotationMirror, 806 * Predicate)} method. Consequently the returned {@link Stream} yields only semantically distinct elements.</p> 807 * 808 * @param ams a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 809 * 810 * @param p a {@link Predicate} that returns {@code true} if a given {@link ExecutableElement}, representing an 811 * annotation element, is to be included in comparison operations; may be {@code null} in which case it is as if 812 * {@code e -> true} were supplied instead 813 * 814 * @return a non-{@code null}, sequential {@link Stream} of {@link AnnotationMirror}s 815 * 816 * @exception NullPointerException if {@code ams} is {@code null} 817 * 818 * @see #sameAnnotation(AnnotationMirror, AnnotationMirror) 819 */ 820 public static final Stream<AnnotationMirror> streamDepthFirst(final Collection<? extends AnnotationMirror> ams, 821 final Predicate<? super ExecutableElement> p) { 822 return ams.isEmpty() ? empty() : streamDepthFirst(ams, new ArrayList<>(17), p); // 17 == arbitrary 823 } 824 825 826 /** 827 * Returns a non-{@code null}, determinate, immutable {@link Set} of {@link ElementType}s describing restrictions 828 * concerning where the annotation interface {@linkplain AnnotationMirror#getAnnotationType() represented} by the 829 * supplied {@link AnnotationMirror} may be applied. 830 * 831 * @param a an {@link AnnotationMirror}; must not be {@code null} 832 * 833 * @return a non-{@code null}, determinate, immutable {@link Set} of {@link ElementType}s describing restrictions 834 * concerning where the annotation interface {@linkplain AnnotationMirror#getAnnotationType() represented} by the 835 * supplied {@link AnnotationMirror} may be applied 836 * 837 * @exception NullPointerException if {@code a} is {@code null} 838 */ 839 public static final Set<ElementType> targetElementTypes(final AnnotationMirror a) { 840 return targetElementTypes((TypeElement)a.getAnnotationType().asElement()); 841 } 842 843 /** 844 * Returns a non-{@code null}, determinate, immutable {@link Set} of {@link ElementType}s describing restrictions 845 * concerning where the supplied annotation interface may be applied. 846 * 847 * @param annotationInterface a {@link TypeElement} representing an {@linkplain 848 * javax.lang.model.element.ElementKind#ANNOTATION_TYPE annotation interface}; must not be {@code null} 849 * 850 * @return a non-{@code null}, determinate, immutable {@link Set} of {@link ElementType}s describing restrictions 851 * concerning where the supplied annotation interface may be applied 852 * 853 * @exception NullPointerException if {@code annotationInterface} is {@code null} 854 * 855 * @see java.lang.annotation.ElementType 856 * 857 * @see java.lang.annotation.Target 858 * 859 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.4.1 Java Language Specification, 860 * section 9.6.4.1 861 */ 862 public static final Set<ElementType> targetElementTypes(final TypeElement annotationInterface) { 863 if (annotationInterface.getKind() == ANNOTATION_TYPE) { 864 for (final AnnotationMirror ma : annotationInterface.getAnnotationMirrors()) { 865 if (((QualifiedNameable)ma.getAnnotationType().asElement()).getQualifiedName().contentEquals("java.lang.annotation.Target")) { 866 @SuppressWarnings("unchecked") 867 final List<? extends AnnotationValue> elementTypes = (List<? extends AnnotationValue>)get(ma, "value"); 868 if (elementTypes.isEmpty()) { 869 break; 870 } 871 final Set<ElementType> s = EnumSet.noneOf(ElementType.class); 872 for (final AnnotationValue av : elementTypes) { 873 s.add(ElementType.valueOf(((VariableElement)av.getValue()).getSimpleName().toString())); 874 } 875 return unmodifiableSet(s); 876 } 877 } 878 } 879 return EMPTY_ELEMENT_TYPES; 880 } 881 882 /** 883 * Returns {@code true} if and only if the supplied {@link ExecutableElement} represents a valid <dfn>annotation 884 * interface element</dfn> as defined by <a 885 * href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1">the Java Language Specification</a>. 886 * 887 * @param e an {@link ExecutableElement}; must not be {@code null} 888 * 889 * @return {@code true} if and only if the supplied {@link ExecutableElement} represents a valid <dfn>annotation 890 * interface element</dfn> as defined by <a 891 * href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1">the Java Language Specification</a> 892 * 893 * @exception NullPointerException if {@code e} is {@code null} 894 * 895 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1 Java Language Specification, section 896 * 9.6.1 897 */ 898 public static final boolean validAnnotationInterfaceElement(final ExecutableElement e) { 899 return 900 e.getKind() == METHOD && 901 e.getEnclosingElement().getKind() == ANNOTATION_TYPE && 902 e.getTypeParameters().isEmpty() && 903 e.getParameters().isEmpty() && 904 e.getThrownTypes().isEmpty() && 905 validAnnotationInterfaceElementType(e.getReturnType()) && 906 (e.getModifiers().isEmpty() || 907 e.getModifiers().equals(EnumSet.of(ABSTRACT)) || 908 e.getModifiers().equals(EnumSet.of(PUBLIC))); 909 } 910 911 /** 912 * Returns {@code true} if and only if the supplied {@link TypeMirror} is a valid type for an <dfn>annotation 913 * interface element</dfn> as defined by <a 914 * href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1">the Java Language Specification</a>. 915 * 916 * @param t a {@link TypeMirror}; must not be {@code null} 917 * 918 * @return {@code true} if and only if the supplied {@link TypeMirror} is a valid type for an <dfn>annotation 919 * interface element</dfn> as defined by <a 920 * href="https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1">the Java Language Specification</a> 921 * 922 * @exception NullPointerException if {@code t} is {@code null} 923 * 924 * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1 Java Language Specification, section 925 * 9.6.1 926 */ 927 public static final boolean validAnnotationInterfaceElementType(final TypeMirror t) { 928 return switch (t) { 929 case null -> throw new NullPointerException("t"); 930 case ArrayType at when at.getKind() == ARRAY -> validAnnotationInterfaceElementScalarType(at.getComponentType()); 931 default -> validAnnotationInterfaceElementScalarType(t); 932 }; 933 } 934 935 static final boolean validAnnotationInterfaceElementScalarType(final TypeMirror t) { 936 return switch (t) { 937 case null -> throw new NullPointerException("t"); 938 case PrimitiveType pt when pt.getKind().isPrimitive() -> true; 939 case DeclaredType dt when dt.getKind() == DECLARED -> { 940 final TypeElement te = (TypeElement)dt.asElement(); 941 yield switch (te.getKind()) { 942 case ANNOTATION_TYPE, ENUM -> true; 943 case CLASS -> { 944 final Name fqn = te.getQualifiedName(); 945 yield fqn.contentEquals("java.lang.Class") || fqn.contentEquals("java.lang.String"); 946 } 947 default -> false; 948 }; 949 } 950 default -> false; 951 }; 952 } 953 954 @SuppressWarnings("unchecked") 955 private static final <K, V> SequencedMap<K, V> emptySequencedMap() { 956 return (SequencedMap<K, V>)EMPTY_MAP; 957 } 958 959 private static final <X> boolean returnTrue(final X ignored) { 960 return true; 961 } 962 963 private static final Stream<AnnotationMirror> streamDepthFirst(final AnnotatedConstruct ac, 964 final Collection<AnnotationMirror> seen, 965 final Predicate<? super ExecutableElement> p) { 966 return streamDepthFirst(ac.getAnnotationMirrors(), seen, p); 967 } 968 969 private static final Stream<AnnotationMirror> streamDepthFirst(final Collection<? extends AnnotationMirror> ams, 970 final Collection<AnnotationMirror> seen, 971 final Predicate<? super ExecutableElement> p) { 972 if (ams.isEmpty()) { 973 return empty(); 974 } 975 // See https://www.techempower.com/blog/2016/10/19/efficient-multiple-stream-concatenation-in-java/ 976 return 977 Stream.of(ams 978 .stream() 979 .sequential() 980 .flatMap(a0 -> { 981 for (final AnnotationMirror a1 : seen) { 982 if (sameAnnotation(a0, a1, p)) { 983 return empty(); 984 } 985 } 986 seen.add(a0); 987 return streamDepthFirst(a0.getAnnotationType().asElement().getAnnotationMirrors(), seen, p); 988 })) 989 .flatMap(identity()); 990 } 991 992}