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}