From 7654cb5c41f8e2316aa039be74a28ff33b0630d9 Mon Sep 17 00:00:00 2001 From: Laird Nelson Date: Fri, 20 Feb 2026 21:03:45 -0800 Subject: [PATCH] Fixes AnnotationMirrors#containsAll bug; cleans up some Constable stuff Signed-off-by: Laird Nelson --- README.md | 2 +- .../microbean/construct/DefaultDomain.java | 13 +-- .../construct/UniversalConstruct.java | 20 +++-- .../construct/constant/Constables.java | 60 ++++++------- .../construct/constant/ConstantDescs.java | 2 + .../construct/element/AnnotationMirrors.java | 89 ++++++++++++++++--- .../construct/element/StringName.java | 16 ++-- .../element/SyntheticAnnotationMirror.java | 48 ++++++---- .../SyntheticAnnotationTypeElement.java | 51 ++++++++++- .../element/SyntheticAnnotationValue.java | 21 +++-- .../construct/element/SyntheticName.java | 14 +-- .../element/UniversalAnnotation.java | 29 +++--- 12 files changed, 252 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index 34a5678..bd639f9 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ dependency: Always check https://search.maven.org/artifact/org.microbean/microbean-construct for up-to-date available versions. --> - 0.0.23 + 0.0.24 ``` diff --git a/src/main/java/org/microbean/construct/DefaultDomain.java b/src/main/java/org/microbean/construct/DefaultDomain.java index 8e68663..f316995 100644 --- a/src/main/java/org/microbean/construct/DefaultDomain.java +++ b/src/main/java/org/microbean/construct/DefaultDomain.java @@ -13,11 +13,8 @@ */ package org.microbean.construct; -import java.lang.constant.ClassDesc; import java.lang.constant.Constable; -import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodHandleDesc; import java.util.List; import java.util.Objects; @@ -54,6 +51,8 @@ import static java.lang.constant.ConstantDescs.BSM_INVOKE; +import static java.lang.constant.MethodHandleDesc.ofConstructor; + /** * A {@linkplain Domain domain of valid Java constructs} that can be used at annotation processing time or at runtime. * @@ -268,10 +267,12 @@ public UniversalType declaredType(DeclaredType enclosingType, } @Override // Constable - public Optional describeConstable() { + public Optional> describeConstable() { return - Optional.of(DynamicConstantDesc.of(BSM_INVOKE, - MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName())))); + Optional.of(DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getClass().getSimpleName(), + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow()))); } @Override // Domain diff --git a/src/main/java/org/microbean/construct/UniversalConstruct.java b/src/main/java/org/microbean/construct/UniversalConstruct.java index 28aba4e..ea13c9d 100644 --- a/src/main/java/org/microbean/construct/UniversalConstruct.java +++ b/src/main/java/org/microbean/construct/UniversalConstruct.java @@ -218,21 +218,23 @@ public final T delegate() { } @Override // Constable - public final Optional describeConstable() { + public final Optional> describeConstable() { final PrimordialDomain primordialDomain = this.domain(); if (domain instanceof Domain d && d instanceof Constable dc) { final T delegate = this.delegate(); final List annotations = this.annotations; // volatile read; may be null and that's OK return Constables.describe(delegate, d) .flatMap(delegateDesc -> Constables.describe(annotations) - .map(annosDesc -> DynamicConstantDesc.of(BSM_INVOKE, - ofConstructor(ClassDesc.of(this.getClass().getName()), - CD_List, - ClassDesc.of(delegate instanceof TypeMirror ? TypeMirror.class.getName() : Element.class.getName()), - ClassDesc.of(PrimordialDomain.class.getName())), - annosDesc, - delegateDesc, - dc.describeConstable().orElseThrow()))); + .map(annosDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getClass().getSimpleName(), + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow(), + CD_List, + (delegate instanceof TypeMirror ? TypeMirror.class : Element.class).describeConstable().orElseThrow(), + PrimordialDomain.class.describeConstable().orElseThrow()), + annosDesc, + delegateDesc, + dc.describeConstable().orElseThrow()))); } return Optional.empty(); } diff --git a/src/main/java/org/microbean/construct/constant/Constables.java b/src/main/java/org/microbean/construct/constant/Constables.java index bcb36eb..e33fb65 100644 --- a/src/main/java/org/microbean/construct/constant/Constables.java +++ b/src/main/java/org/microbean/construct/constant/Constables.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2024 microBean™. + * Copyright © 2024–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 @@ -81,6 +81,7 @@ import static org.microbean.construct.constant.ConstantDescs.CD_TypeParameterElement; import static org.microbean.construct.constant.ConstantDescs.CD_TypeMirror; import static org.microbean.construct.constant.ConstantDescs.CD_TypeVariable; +import static org.microbean.construct.constant.ConstantDescs.CD_VariableElement; import static org.microbean.construct.constant.ConstantDescs.CD_WildcardType; /** @@ -119,7 +120,7 @@ public static final Optional describe(final Name n, fina default -> (d instanceof Constable c ? c.describeConstable() : Optional.empty()) .map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "name", MethodTypeDesc.of(CD_Name, CD_CharSequence)), @@ -218,7 +219,7 @@ public static final Optional describe(final ExecutableEl final ConstantDesc[] args = new ConstantDesc[5 + parameterCount]; args[0] = ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "executableElement", MethodTypeDesc.of(CD_ExecutableElement, CD_TypeElement, @@ -271,7 +272,7 @@ public static final Optional describe(final ModuleElemen default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "moduleElement", MethodTypeDesc.of(CD_ModuleElement, CD_CharSequence)), @@ -300,7 +301,7 @@ public static final Optional describe(final PackageEleme default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "packageElement", MethodTypeDesc.of(CD_PackageElement, CD_CharSequence)), @@ -329,7 +330,7 @@ public static final Optional describe(final TypeElement default -> describe(e.getQualifiedName(), d) // getQualifiedName() does not cause symbol completion .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "typeElement", MethodTypeDesc.of(CD_TypeElement, CD_CharSequence)), @@ -361,7 +362,7 @@ yield describe(e.getEnclosingElement(), d) .flatMap(parameterizableDesc -> describe(e.getSimpleName(), d) .map(nameDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "typeParameterElement", MethodTypeDesc.of(CD_TypeParameterElement, CD_Parameterizable, @@ -396,7 +397,7 @@ public static final Optional describe(final RecordCompon yield describe((TypeElement)e.getEnclosingElement(), d) .map(executableDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "recordComponentElement", MethodTypeDesc.of(CD_RecordComponentElement, CD_ExecutableElement)), @@ -430,11 +431,13 @@ yield describe(e.getSimpleName(), d) .flatMap(nameDesc -> describe(e.getEnclosingElement(), d) .map(enclosingElementDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "variableElement", - MethodTypeDesc.of(CD_Element, + MethodTypeDesc.of(CD_VariableElement, + CD_Element, CD_CharSequence)), ((Constable)d).describeConstable().orElseThrow(), + enclosingElementDesc, nameDesc))); } } @@ -498,7 +501,7 @@ public static final Optional describe(final ArrayType t, yield describe(t.getComponentType(), d) .map(componentTypeDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "arrayTypeOf", MethodTypeDesc.of(CD_ArrayType, CD_TypeMirror)), @@ -540,7 +543,7 @@ yield switch (t.getKind()) { final TypeMirror enclosingType = t.getEnclosingType(); // Call args[0] = ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "declaredType", MethodTypeDesc.of(CD_DeclaredType, CD_DeclaredType, @@ -597,7 +600,7 @@ public static final Optional describe(final NoType t, fi yield t.getKind().describeConstable() .map(typeKindDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "noType", MethodTypeDesc.of(CD_NoType, CD_TypeKind)), @@ -628,7 +631,7 @@ public static final Optional describe(final NullType t, default -> (d instanceof Constable c ? c.describeConstable() : Optional.empty()) .map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "nullType", MethodTypeDesc.of(CD_NullType)), domainDesc)); @@ -661,7 +664,7 @@ public static final Optional describe(final PrimitiveTyp yield t.getKind().describeConstable() .map(typeKindDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "primitiveType", MethodTypeDesc.of(CD_PrimitiveType, CD_TypeKind)), @@ -703,7 +706,7 @@ public static final Optional describe(final TypeVariable final String name = d.toString(e.getSimpleName()); yield Optional.of(DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "typeVariable", MethodTypeDesc.of(CD_TypeVariable, CD_Parameterizable, @@ -740,7 +743,7 @@ yield describe(t.getExtendsBound(), d) .flatMap(extendsBoundDesc -> describe(t.getSuperBound(), d) .map(superBoundDesc -> DynamicConstantDesc.of(BSM_INVOKE, ofMethod(VIRTUAL, - ClassDesc.of(Domain.class.getName()), + Domain.class.describeConstable().orElseThrow(), "wildcardType", MethodTypeDesc.of(CD_WildcardType, CD_TypeMirror, @@ -754,10 +757,8 @@ yield describe(t.getExtendsBound(), d) } /** - * Returns a nominal descriptor for the supplied {@link List}, or an {@linkplain Optional#empty() empty} {@link - * Optional} if the supplied {@link List} cannot be described. - * - * @param the supplied {@code list}'s element type + * Returns a non-{@code null} nominal descriptor for the supplied {@link List}, or an {@linkplain Optional#empty() + * empty} {@link Optional} if the supplied {@link List} cannot be described. * * @param list a {@link List} to be described; may be {@code null}; if non-{@code null} must be immutable and * must not contain {@code null} elements or undefined behavior will result @@ -766,10 +767,10 @@ yield describe(t.getExtendsBound(), d) * * @see #describe(List, Function) */ - public static final Optional describe(final List list) { + public static final Optional describe(final List list) { return describe(list, e -> e instanceof Constable c ? c.describeConstable() : Optional.empty()); } - + /** * Returns a nominal descriptor for the supplied {@link List}, or an {@linkplain Optional#empty() empty} {@link * Optional} if the supplied {@link List} cannot be described. @@ -814,14 +815,14 @@ public static final Optional describe(final List Optional describe(final Map e : map.entrySet()) { @@ -891,9 +892,8 @@ public static Optional describe(final Map allAnnotati return m.isEmpty() ? emptySequencedMap() : unmodifiableSequencedMap(m); } + /** + * Returns {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link + * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as + * the supplied {@link AnnotationMirror}. + * + * @param c a non-{@code null} {@link Collection} of {@link AnnotationMirror}s + * + * @param a a non-{@code null} {@link AnnotationMirror} + * + * @return {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link + * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as + * the supplied {@link AnnotationMirror} + * + * @exception NullPointerException if {@code c} or {@code a} is {@code null} + * + * @see #contains(collection, AnnotationMirror, Predicate) + */ + public static final boolean contains(final Collection c, + final AnnotationMirror a) { + return contains(c, a, null); + } + /** * Returns {@code true} if and only if the supplied {@link Collection} of {@link AnnotationMirror}s contains an {@link * AnnotationMirror} that is {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) the same} as @@ -199,13 +221,12 @@ public static final SequencedMap allAnnotati * @exception NullPointerException if {@code c} or {@code a} is {@code null} * * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) + * + * @see #containsAll(collection, Collection, Predicate) */ public static final boolean contains(final Collection c, final AnnotationMirror a, final Predicate p) { - if (c.isEmpty()) { - return false; - } for (final AnnotationMirror ca : c) { if (sameAnnotation(ca, a, p)) { return true; @@ -215,7 +236,27 @@ public static final boolean contains(final Collection c0, + final Collection c1) { + return containsAll(c0, c1, null); + } + + /** + * Returns {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1}, * * @param c0 a non-{@code null} {@link Collection} of {@link AnnotationMirror}s @@ -226,11 +267,13 @@ public static final boolean contains(final Collection true} were supplied instead * - * @return {@code true} if and only if {@code c0} contains {@linkplain #sameAnnotation(AnnotationMirror, + * @return {@code true} if and only if {@code c0} contains all {@linkplain #sameAnnotation(AnnotationMirror, * AnnotationMirror, Predicate) the same} {@link AnnotationMirror}s as are found in {@code c1} * * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} * + * @see #contains(Collection, AnnotationMirror, Predicate) + * * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) */ public static final boolean containsAll(final Collection c0, @@ -239,14 +282,10 @@ public static final boolean containsAll(final Collection c0, + final Collection c1) { + return sameAnnotations(c0, c1, null); + } + /** * Returns {@code true} if {@code c0} has all the {@linkplain #sameAnnotation(AnnotationMirror, AnnotationMirror, * Predicate) same annotations} as {@code c1}, and if {@code c1} has all the {@linkplain @@ -539,6 +600,8 @@ public static final boolean sameAnnotation(final AnnotationMirror am0, * * @exception NullPointerException if either {@code c0} or {@code c1} is {@code null} * + * @see #containsAll(Collection, Collection, Predicate) + * * @see #sameAnnotation(AnnotationMirror, AnnotationMirror, Predicate) */ public static final boolean sameAnnotations(final Collection c0, diff --git a/src/main/java/org/microbean/construct/element/StringName.java b/src/main/java/org/microbean/construct/element/StringName.java index 5af677d..55959f3 100644 --- a/src/main/java/org/microbean/construct/element/StringName.java +++ b/src/main/java/org/microbean/construct/element/StringName.java @@ -113,14 +113,16 @@ public final boolean contentEquals(final CharSequence cs) { } @Override // Constable - public final Optional describeConstable() { + public final Optional> describeConstable() { return (this.domain() instanceof Constable c ? c.describeConstable() : Optional.empty()) - .map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE, - MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()), - ClassDesc.of(CharSequence.class.getName()), - ClassDesc.of(PrimordialDomain.class.getName())), - this.value, - domainDesc)); + .map(domainDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.value, + this.getClass().describeConstable().orElseThrow(), + MethodHandleDesc.ofConstructor(this.getClass().describeConstable().orElseThrow(), + CharSequence.class.describeConstable().orElseThrow(), + PrimordialDomain.class.describeConstable().orElseThrow()), + this.value, + domainDesc)); } @Override // Record diff --git a/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java b/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java index 84b628d..8ad0295 100644 --- a/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java +++ b/src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java @@ -29,6 +29,7 @@ import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; @@ -42,6 +43,8 @@ import static java.util.Collections.unmodifiableMap; +import static java.util.HashMap.newHashMap; + import static java.util.LinkedHashMap.newLinkedHashMap; import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE; @@ -152,6 +155,7 @@ public SyntheticAnnotationMirror(final TypeElement annotationTypeElement, * * @exception NullPointerException if {@code a} is {@code null} */ + // (Copy constructor.) public SyntheticAnnotationMirror(final AnnotationMirror a) { super(); this.annotationTypeElement = new SyntheticAnnotationTypeElement((TypeElement)a.getAnnotationType().asElement()); @@ -184,17 +188,19 @@ public SyntheticAnnotationMirror(final AnnotationMirror a) { @Override // Constable - public final Optional describeConstable() { - return this.annotationTypeElement instanceof Constable c ? c.describeConstable() : Optional.empty() - .flatMap(elementDesc -> Constables.describe(this.elementValues, - SyntheticAnnotationMirror::describeExecutableElement, + public final Optional> describeConstable() { + return (this.annotationTypeElement instanceof Constable c ? c.describeConstable() : Optional.empty()) + .flatMap(elementDesc -> Constables.describe(this.toSyntheticValues(), + String::describeConstable, SyntheticAnnotationMirror::describeAnnotationValue) - .map(valuesDesc -> DynamicConstantDesc.of(BSM_INVOKE, - ofConstructor(ClassDesc.of(this.getClass().getName()), - ClassDesc.of(TypeElement.class.getName()), - CD_Map), - elementDesc, - valuesDesc))); + .map(valuesDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getAnnotationType().asElement().getSimpleName().toString(), // supposed to be unqualified, I guess + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow(), + TypeElement.class.describeConstable().orElseThrow(), + CD_Map), + elementDesc, + valuesDesc))); } @Override // AnnotationMirror @@ -212,12 +218,25 @@ public final String toString() { return "@" + this.annotationTypeElement.toString(); // TODO: not anywhere near good enough } + // Called by describeConstable(). + private final Map toSyntheticValues() { + if (this.elementValues.isEmpty()) { + return Map.of(); + } + final Map rv = newHashMap(this.elementValues.size()); + for (final Entry e : this.elementValues.entrySet()) { + rv.put(e.getKey().getSimpleName().toString(), e.getValue().getValue()); + } + return rv; + } + /* * Static methods. */ + // Called by describeConstable(). private static final Optional describeAnnotationValue(final Object v) { return switch (v) { case null -> Optional.empty(); // deliberately not Optional.of(NULL); annotation values cannot be null @@ -228,15 +247,6 @@ private static final Optional describeAnnotationValue(fi }; } - private static final Optional describeExecutableElement(final ExecutableElement e) { - return switch (e) { - case null -> throw new IllegalStateException(); - case Constable c -> c.describeConstable(); - case ConstantDesc cd -> Optional.of(cd); - default -> Optional.empty(); - }; - } - private static final E element(final Iterable elements, final CharSequence simpleName) { for (final E e : elements) { if (e.getSimpleName().contentEquals(simpleName)) { diff --git a/src/main/java/org/microbean/construct/element/SyntheticAnnotationTypeElement.java b/src/main/java/org/microbean/construct/element/SyntheticAnnotationTypeElement.java index 2a51a15..cce8d1c 100644 --- a/src/main/java/org/microbean/construct/element/SyntheticAnnotationTypeElement.java +++ b/src/main/java/org/microbean/construct/element/SyntheticAnnotationTypeElement.java @@ -15,9 +15,14 @@ import java.lang.annotation.Annotation; +import java.lang.constant.Constable; +import java.lang.constant.ConstantDesc; +import java.lang.constant.DynamicConstantDesc; + import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -44,8 +49,15 @@ import javax.lang.model.type.TypeVariable; import javax.lang.model.type.TypeVisitor; +import org.microbean.construct.constant.Constables; + import org.microbean.construct.type.NoneType; +import static java.lang.constant.ConstantDescs.BSM_INVOKE; +import static java.lang.constant.ConstantDescs.CD_List; + +import static java.lang.constant.MethodHandleDesc.ofConstructor; + import static java.util.Collections.unmodifiableList; import static java.util.Objects.requireNonNull; @@ -70,7 +82,7 @@ * * @see SyntheticAnnotationMirror */ -public final class SyntheticAnnotationTypeElement implements TypeElement { +public final class SyntheticAnnotationTypeElement implements Constable, TypeElement { /* @@ -299,6 +311,7 @@ public SyntheticAnnotationTypeElement(final List ann * @exception IllegalArgumentException if the supplied {@link TypeElement}'s {@link TypeElement#getKind() getKind()} * method does not return {@link javax.lang.model.element.ElementKind#ANNOTATION_TYPE} */ + // (Copy constructor.) public SyntheticAnnotationTypeElement(final TypeElement e) { super(); if (e.getKind() != ANNOTATION_TYPE) { @@ -348,6 +361,7 @@ public SyntheticAnnotationTypeElement(final TypeElement e) { * * @see SyntheticAnnotationMirror */ + // (Canonical.) public SyntheticAnnotationTypeElement(final List annotationMirrors, final SyntheticName fullyQualifiedName, final List elements) { @@ -357,7 +371,7 @@ public SyntheticAnnotationTypeElement(final List ann final int i = fqn.lastIndexOf('.'); this.sn = i >= 0 ? new SyntheticName(fqn.substring(i + 1)) : fullyQualifiedName; this.fqn = fullyQualifiedName; - this.type = new Type(); + this.type = new Type(); // inner class on purpose if (elements.isEmpty()) { this.elements = List.of(); } else { @@ -385,6 +399,22 @@ public final TypeMirror asType() { return this.type; } + @Override // Constable + public final Optional> describeConstable() { + return Constables.describe(this.annotationMirrors) + .flatMap(amsDesc -> Constables.describe(InternalAnnotationElement.toSyntheticAnnotationElements(this.elements)) + .map(elementsDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getSimpleName().toString(), + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow(), + CD_List, + SyntheticName.class.describeConstable().orElseThrow(), + CD_List), + amsDesc, + this.fqn.describeConstable().orElseThrow(), + elementsDesc))); + } + @Override // TypeElement (AnnotatedConstruct) public final List getAnnotationMirrors() { return this.annotationMirrors; @@ -882,6 +912,23 @@ public final boolean isVarArgs() { } + /* + * Static methods. + */ + + + private static List toSyntheticAnnotationElements(final List iaes) { + if (iaes.isEmpty()) { + return List.of(); + } + final List saes = new ArrayList<>(iaes.size()); + for (final InternalAnnotationElement iae : iaes) { + saes.add(new SyntheticAnnotationElement(iae.annotationMirrors, iae.t, iae.name, iae.defaultValue)); + } + return unmodifiableList(saes); + } + + /* * Inner and nested classes. */ diff --git a/src/main/java/org/microbean/construct/element/SyntheticAnnotationValue.java b/src/main/java/org/microbean/construct/element/SyntheticAnnotationValue.java index 0d2675f..06a81c2 100644 --- a/src/main/java/org/microbean/construct/element/SyntheticAnnotationValue.java +++ b/src/main/java/org/microbean/construct/element/SyntheticAnnotationValue.java @@ -28,6 +28,8 @@ 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_Object; @@ -114,12 +116,19 @@ public final R accept(final AnnotationValueVisitor v, final P p) { } @Override // Constable - public final Optional describeConstable() { - return this.value instanceof Constable c ? c.describeConstable() : Optional.empty() - .map(valueDesc -> DynamicConstantDesc.of(BSM_INVOKE, - ofConstructor(ClassDesc.of(this.getClass().getName()), - CD_Object), - valueDesc)); + public final Optional> describeConstable() { + final Optional valueDescOptional = switch (this.value) { + case Constable c -> c.describeConstable(); + case ConstantDesc cd -> Optional.of(cd); + case List l -> Constables.describe(l); + default -> Optional.empty(); + }; + return valueDescOptional.map(valueDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getClass().getSimpleName(), + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow(), + CD_Object), + valueDesc)); } @Override // Object diff --git a/src/main/java/org/microbean/construct/element/SyntheticName.java b/src/main/java/org/microbean/construct/element/SyntheticName.java index beefc96..ef05402 100644 --- a/src/main/java/org/microbean/construct/element/SyntheticName.java +++ b/src/main/java/org/microbean/construct/element/SyntheticName.java @@ -29,7 +29,7 @@ import static java.lang.constant.ConstantDescs.BSM_INVOKE; import static java.lang.constant.ConstantDescs.CD_String; -import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC; +import static java.lang.constant.MethodHandleDesc.ofConstructor; import static java.util.Objects.requireNonNull; @@ -114,12 +114,12 @@ public final boolean contentEquals(final CharSequence cs) { @Override // Constable public final Optional> describeConstable() { return - Optional.of(DynamicConstantDesc.of(BSM_INVOKE, - MethodHandleDesc.ofMethod(STATIC, - ClassDesc.of(this.getClass().getName()), - "of", - MethodTypeDesc.of(CD_String)), - this.value)); + Optional.of(DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.value, + this.getClass().describeConstable().orElseThrow(), + ofConstructor(this.getClass().describeConstable().orElseThrow(), + CD_String), + this.value)); } @Override // Object diff --git a/src/main/java/org/microbean/construct/element/UniversalAnnotation.java b/src/main/java/org/microbean/construct/element/UniversalAnnotation.java index 4268369..e7baa6c 100644 --- a/src/main/java/org/microbean/construct/element/UniversalAnnotation.java +++ b/src/main/java/org/microbean/construct/element/UniversalAnnotation.java @@ -13,7 +13,6 @@ */ package org.microbean.construct.element; -import java.lang.constant.ClassDesc; import java.lang.constant.Constable; import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; @@ -123,18 +122,22 @@ public final AnnotationMirror delegate() { } @Override // Constable - public Optional describeConstable() { - return this.domain instanceof Constable c0 ? c0.describeConstable() : Optional.empty() - .flatMap(primordialDomainDesc -> this.delegate() instanceof Constable c1 ? c1.describeConstable() : Optional.empty() - .map(delegateDesc -> DynamicConstantDesc.of(BSM_INVOKE, - ofMethod(STATIC, - ClassDesc.of(this.getClass().getName()), - "of", - MethodTypeDesc.of(ClassDesc.of(this.getClass().getName()), - ClassDesc.of(AnnotationMirror.class.getName()), - ClassDesc.of(PrimordialDomain.class.getName()))), - delegateDesc, - primordialDomainDesc))); + public final Optional> describeConstable() { + // TODO: this.delegate() is never going to be a Constable. It's debatable whether this class should implement + // Constable at all. + return (this.domain instanceof Constable c0 ? c0.describeConstable() : Optional.empty()) + .flatMap(primordialDomainDesc -> (this.delegate() instanceof Constable c1 ? c1.describeConstable() : Optional.empty()) + .map(delegateDesc -> DynamicConstantDesc.ofNamed(BSM_INVOKE, + this.getAnnotationType().asElement().getSimpleName().toString(), + UniversalAnnotation.class.describeConstable().orElseThrow(), + ofMethod(STATIC, + UniversalAnnotation.class.describeConstable().orElseThrow(), + "of", + MethodTypeDesc.of(UniversalAnnotation.class.describeConstable().orElseThrow(), + AnnotationMirror.class.describeConstable().orElseThrow(), + PrimordialDomain.class.describeConstable().orElseThrow())), + delegateDesc, + primordialDomainDesc))); } /**