This {@link Processor} will be invoked by a {@link BlockingCompilationTask} as part of an invocation of its
+ * {@link BlockingCompilationTask#run()} method. Its {@link #init(ProcessingEnvironment)} method will be invoked as
+ * part of {@linkplain javax.annotation.processing.Processor the standard Processor lifecycle}. It will
+ * call the {@link Consumer#accept(Object) accept(ProcessingEnvironment)} method on the supplied {@link
+ * Consumer}. Then it will block until {@link #close()} is invoked (from a separate thread, obviously). Before
+ * exiting, it will invoke the {@link Runnable#run() run()} method of the supplied {@link Runnable}.
List} when invoked, regardless of
+ * arguments.
+ *
+ * @param element ignored; may be {@code null}
+ *
+ * @param annotation ignored; may be {@code null}
+ *
+ * @param member ignored; may be {@code null}
+ *
+ * @param userText ignored; may be {@code null}
+ *
+ * @return an {@linkplain List#of() empty, immutable, determinate List} when invoked, regardless of
+ * arguments
+ */
@Override // Processor
public final Iterable extends Completion> getCompletions(final Element element,
final AnnotationMirror annotation,
@@ -116,21 +162,43 @@ public final Iterable extends Completion> getCompletions(final Element element
return List.of();
}
+ /**
+ * Returns an {@linkplain Set#of() empty, immutable, determinate Set} when invoked.
+ *
+ * @return an {@linkplain Set#of() empty, immutable, determinate Set} when invoked
+ */
@Override // Processor
public final SetSet} when invoked.
+ *
+ * @return an {@linkplain Set#of() empty, immutable, determinate Set} when invoked
+ */
@Override // Processor
public final SetEach {@link ExecutableElement} represents an annotation element and meets the + * requirements of such an element.
+ * + *Each {@link AnnotationValue} represents the value of an annotation element and meets the requirements for + * annotation values.
+ * + *This method is a more capable, better-typed replacement of the {@link + * javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror)} method, and should be preferred.
+ * + * @param a an {@link AnnotationMirror}; may be {@code null} in which case an empty, immutable, determinate {@link + * Map} will be returned + * + * @return an immutable, determinate {@link Map} of {@link AnnotationValue} instances indexed by {@link + * ExecutableElement}s + * + * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1 Java Language Specification, section + * 9.6.1 + * + * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror) + */ + public static final SequencedMapUnlike some other annotation-processing-related facilities, the relation represented by this {@link + * SameAnnotationValueVisitor} does not require that the values being logically compared originate from {@link + * AnnotationValue} instances from the same vendor or toolkit.
+ * + *The second argument passed to {@link #visit(AnnotationValue, Object)} is expected to be either {@code null}, an + * {@link AnnotationValue}, or the result of an invocation of an {@link AnnotationValue}'s {@link + * AnnotationValue#getValue() getValue()} method.
+ * + *Any two {@link TypeElement}s encountered during traversal are considered equal if their {@linkplain + * TypeElement#getQualifiedName() qualified names} have {@linkplain + * javax.lang.model.element.Name#contentEquals(CharSequence) equal contents}.
+ * + *Any two {@link VariableElement}s representing enum constants encountered during traversal are considered equal if + * their {@linkplain VariableElement#getSimpleName() simple names} have {@linkplain + * javax.lang.model.element.Name#contentEquals(CharSequence) equal contents}.
+ * + * @author Laird Nelson + * + * @see AnnotationValue#accept(javax.lang.model.element.AnnotationValueVisitor, Object) + * + * @see AnnotationMirrors#allAnnotationValues(AnnotationMirror) + */ +public final class SameAnnotationValueVisitor extends AbstractAnnotationValueVisitor14String conversion of}
- * the supplied {@link CharSequence}, and whose {@link #domain()} method will return a {@link PrimordialDomain} {@linkplain
- * #equals(Object) equal to} the supplied {@link PrimordialDomain}.
+ * String#equals(Object) equal to} the {@linkplain PrimordialDomain#toString(CharSequence) String
+ * conversion of} the supplied {@link CharSequence}, and whose {@link #domain()} method will return a {@link
+ * PrimordialDomain} {@linkplain #equals(Object) equal to} the supplied {@link PrimordialDomain}.
*
* @param cs a {@link CharSequence}; must not be {@code null}
*
diff --git a/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java b/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java
index e0fc4a3..e430e44 100644
--- a/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java
+++ b/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java
@@ -1,6 +1,6 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
- * Copyright © 2025 microBean™.
+ * Copyright © 2025–2026 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@@ -13,66 +13,90 @@
*/
package org.microbean.construct.element;
-import java.lang.annotation.Annotation;
-
import java.lang.constant.ClassDesc;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
import java.lang.constant.DynamicConstantDesc;
-import java.lang.constant.MethodTypeDesc;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Optional;
-import java.util.function.Function;
-
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.AnnotationValueVisitor;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
import org.microbean.construct.constant.Constables;
import static java.lang.constant.ConstantDescs.BSM_INVOKE;
import static java.lang.constant.ConstantDescs.CD_Map;
-import static java.lang.constant.ConstantDescs.CD_Object;
-import static java.lang.constant.ConstantDescs.NULL;
-
-import static java.lang.constant.DirectMethodHandleDesc.Kind.INTERFACE_STATIC;
import static java.lang.constant.MethodHandleDesc.ofConstructor;
-import static java.util.Arrays.fill;
-
import static java.util.Collections.unmodifiableMap;
import static java.util.LinkedHashMap.newLinkedHashMap;
-import static java.util.Objects.requireNonNull;
-
import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE;
-import static javax.lang.model.element.ElementKind.METHOD;
+
+import static javax.lang.model.util.ElementFilter.methodsIn;
/**
* An experimental {@link AnnotationMirror} implementation that is partially or wholly synthetic.
*
+ * It is possible to create {@link SyntheticAnnotationMirror} instances representing annotations that a Java compiler + * will not produce. For example, annotations cannot refer to each + * other, directly or indirectly, but two {@link SyntheticAnnotationMirror}s may do so.
+ * * @author Laird Nelson + * + * @spec https://docs.oracle.com/javase/specs/jls/se25/html/jls-9.html#jls-9.6.1 Java Language Specification, section + * 9.6.1 */ public final class SyntheticAnnotationMirror implements AnnotationMirror, Constable { + + /* + * Instance fields. + */ + + private final TypeElement annotationTypeElement; private final MapIf {@code value} is a {@link SyntheticAnnotationValue}, then it is returned unchanged.
+ * + * @param value a value legal for an {@link AnnotationValue}; must not be {@code null} + * + * @return a non-{@code null}, determinate {@link SyntheticAnnotationValue} + * + * @exception NullPointerException if {@code value} is {@code null} + * + * @exception IllegalArgumentException if {@code value} is not legal for an {@link AnnotationValue} + * + * @see AnnotationValue + */ + public static final SyntheticAnnotationValue of(final Object value) { + return switch (value) { + case null -> throw new NullPointerException("value"); + case SyntheticAnnotationValue sav -> sav; + default -> new SyntheticAnnotationValue(value); + }; + } + + private static final Object value(final Object value) { + return switch (value) { + case null -> throw new NullPointerException("value"); + + case AnnotationValue av -> av.getValue(); // not part of the spec; just good hygiene + + case List> l -> l.stream().map(SyntheticAnnotationValue::new).toList(); + + case TypeMirror t -> switch (t.getKind()) { + case ARRAY, BOOLEAN, BYTE, CHAR, DECLARED, DOUBLE, FLOAT, INT, LONG, SHORT, VOID -> t; + default -> throw new IllegalArgumentException("value: " + value); + }; + + case VariableElement e -> switch (e.getKind()) { + case ENUM_CONSTANT -> e; + default -> throw new IllegalArgumentException("value: " + value); + }; + + case AnnotationMirror a -> a; + case Boolean b -> b; + case Byte b -> b; + case Character c -> c; + case Double d -> d; + case Float f -> f; + case Integer i -> i; + case Long l -> l; + case Short s -> s; + case String s -> s; + + default -> throw new IllegalArgumentException("value: " + value); + }; + } + +} diff --git a/src/main/java/org/microbean/construct/element/SyntheticName.java b/src/main/java/org/microbean/construct/element/SyntheticName.java index 116132a..98dde45 100644 --- a/src/main/java/org/microbean/construct/element/SyntheticName.java +++ b/src/main/java/org/microbean/construct/element/SyntheticName.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2025 microBean™. + * Copyright © 2025–2026 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -22,9 +22,6 @@ import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import java.util.stream.IntStream; import javax.lang.model.element.Name; @@ -50,10 +47,20 @@ */ public final class SyntheticName implements Constable, Name { - private static final ConcurrentMap