diff --git a/src/main/java/org/microbean/construct/Domain.java b/src/main/java/org/microbean/construct/Domain.java index 6ca2125..6bf6053 100644 --- a/src/main/java/org/microbean/construct/Domain.java +++ b/src/main/java/org/microbean/construct/Domain.java @@ -17,6 +17,7 @@ import java.util.Objects; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.Name; @@ -87,8 +88,8 @@ public interface Domain { public ArrayType arrayTypeOf(final TypeMirror componentType); /** - * Returns the {@link Element} declaring the supplied {@link TypeMirror}, or {@code null} if there is no such {@link - * Element}. + * Returns the {@link Element} declaring the supplied {@link TypeMirror}, or {@code null} if there is no such + * {@link Element}. * * @param t a {@link TypeMirror}; must not be {@code null} * @@ -210,8 +211,8 @@ public interface Domain { /** * A convenience method that returns the {@link DeclaredType} {@linkplain TypeElement#asType() of} a {@link - * TypeElement} that bears the supplied {@code canonicalName}, or {@code null} if there is no such {@link TypeElement} - * (and therefore no such {@link DeclaredType}). + * TypeElement} that bears the supplied {@code canonicalName}, or {@code null} if there is no such {@link + * TypeElement} (and therefore no such {@link DeclaredType}). * * @param canonicalName a valid canonical name; must not be {@code null} * @@ -324,8 +325,8 @@ public DeclaredType declaredType(final DeclaredType enclosingType, /** * Returns the {@link Element} responsible for declaring the supplied {@link TypeMirror}, which is most commonly a * {@link DeclaredType}, a {@link TypeVariable}, a {@link NoType} with a {@link TypeKind} of {@link TypeKind#MODULE}, - * or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}, or {@code null} if there is no such {@link - * Element}. + * or a {@link NoType} with a {@link TypeKind} of {@link TypeKind#PACKAGE}, or {@code null} if there is no + * such {@link Element}. * * @param t a {@link TypeMirror}; must not be {@code null} * @@ -337,6 +338,29 @@ public DeclaredType declaredType(final DeclaredType enclosingType, */ public Element element(final TypeMirror t); + /** + * A convenience method that returns the element type of the supplied {@link TypeMirror}. + * + *
The element type of an {@linkplain TypeKind#ARRAY array type} is the element type of its {@linkplain + * ArrayType#getComponentType() component type}.
. + * + *The element type of every other kind of type is the type itself. Note that the semantics of the prior sentence + * diverge deliberately, primarily for convenience, from those of the relevant section in the Java Language + * Specification.
+ * + * @param t a {@link TypeMirror}; must not be {@code null} + * + * @return the element type of the supplied {@link TypeMirror}; never {@code null} + * + * @exception NullPointerException if {@code t} is {@code null} + * + * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-10.html#jls-10.1 Java Language Specification, section + * 10.1 + */ + public default TypeMirror elementType(final TypeMirror t) { + return t.getKind() == TypeKind.ARRAY ? this.elementType(((ArrayType)t).getComponentType()) : t; + } + /** * Returns the erasure of the supplied {@link TypeMirror}. * @@ -360,7 +384,8 @@ public DeclaredType declaredType(final DeclaredType enclosingType, /** * A convenience method that returns an {@link ExecutableElement} representing the static initializer, constructor or - * method described by the supplied arguments, or {@code null} if no such {@link ExecutableElement} exists. + * method described by the supplied arguments, or {@code null} if no such {@link ExecutableElement} + * exists. * * @param declaringElement a {@link TypeElement} representing the class that declares the executable; must not be * {@code null} @@ -373,9 +398,8 @@ public DeclaredType declaredType(final DeclaredType enclosingType, * @param parameterTypes {@link TypeMirror}s that represent the executable's {@linkplain * ExecutableElement#getParameters() parameter types} * - * @return an {@link ExecutableElement} with an {@link javax.lang.model.element.ElementKind} of {@link - * javax.lang.model.element.ElementKind#CONSTRUCTOR}, {@link javax.lang.model.element.ElementKind#METHOD}, or {@link - * javax.lang.model.element.ElementKind#STATIC_INIT}, or {@code null} + * @return an {@link ExecutableElement} with an {@link ElementKind} of {@link ElementKind#CONSTRUCTOR}, {@link + * ElementKind#METHOD}, or {@link ElementKind#STATIC_INIT}, or {@code null} * * @exception NullPointerException if any argument is {@code null} */ @@ -444,6 +468,42 @@ public default boolean generic(final Element e) { return false; } + /** + * A convenience method that returns {@code true} if and only if the supplied {@link Element} represents the (essentially + * primordial) {@code java.lang.Object} {@link Element}. + * + * @param e an {@link Element}; must not be {@code null} + * + * @return {@code true} if and only if the supplied {@link Element} represents the (essentially + * primordial) {@code java.lang.Object} {@link Element}; {@code false} otherwise + * + * @exception NullPointerException if {@code e} is {@code null} + */ + public default boolean javaLangObject(final Element e) { + return + e.getKind() == ElementKind.CLASS && + ((QualifiedNameable)e).getQualifiedName().contentEquals("java.lang.Object"); + } + + /** + * A convenience method that returns {@code true} if and only if the supplied {@link TypeMirror} represents the {@link + * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element. + * + * @param t a {@link TypeMirror}; must not be {@code null} + * + * @return {@code true} represents the {@link + * DeclaredType} declared by the (essentially primordial) {@code java.lang.Object} element; {@code false} otherwise + * + * @exception NullPointerException if {@code t} is {@code null} + * + * @see #javaLangObject(Element) + */ + public default boolean javaLangObject(final TypeMirror t) { + return + t.getKind() == TypeKind.DECLARED && + javaLangObject(((DeclaredType)t).asElement()); + } + /** * A convenience method that returns the {@link TypeElement} representing the class named {@link Object * java.lang.Object}. @@ -471,7 +531,7 @@ public default TypeElement javaLangObject() { /** * Returns a {@link ModuleElement} representing the module {@linkplain ModuleElement#getQualifiedName() named} by the - * supplied {@code qualifiedName}, or {@code null} if there is no such {@link ModuleElement}. + * supplied {@code qualifiedName}, or {@code null} if there is no such {@link ModuleElement}. * * @param qualifiedName a name suitable for naming a module; must not be {@code null}; may be {@linkplain * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an unnamed module will @@ -540,8 +600,8 @@ public default TypeElement javaLangObject() { public NullType nullType(); /** - * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName}, or {@code null} - * if there is no such {@link PackageElement}. + * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName}, or + * {@code null} if there is no such {@link PackageElement}. * * @param canonicalName a canonical name suitable for naming a package; must not be {@code null}; may be {@linkplain * CharSequence#isEmpty() empty}, in which case a {@link ModuleElement} representing an unnamed package will @@ -560,8 +620,8 @@ public default TypeElement javaLangObject() { /** * Returns a {@link PackageElement} representing the package bearing the supplied {@code canonicalName} as seen from - * the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such {@link - * PackageElement}. + * the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such {@link + * PackageElement}. * * @param asSeenFrom a {@link ModuleElement}; must not be {@code null} * @@ -580,6 +640,25 @@ public default TypeElement javaLangObject() { */ public PackageElement packageElement(final ModuleElement asSeenFrom, final CharSequence canonicalName); + /** + * A convenience method that returns {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain + * TypeMirror#getKind() has aTypeKind} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
+ * DeclaredType#getTypeArguments() has an empty type arguments list}.
+ *
+ * @param t a {@link TypeMirror}; must not be {@code null}
+ *
+ * @return {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain
+ * TypeMirror#getKind() has a TypeKind} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain
+ * DeclaredType#getTypeArguments() has an empty type arguments list}; {@code false} otherwise
+ *
+ * @exception NullPointerException if {@code t} is {@code null}
+ */
+ public default boolean parameterized(final TypeMirror t) {
+ return
+ t.getKind() == TypeKind.DECLARED &&
+ !((DeclaredType)t).getTypeArguments().isEmpty();
+ }
+
/**
* Returns the result of applying unboxing conversion to the (logical) {@link TypeElement} bearing the
* supplied {@code canonicalName}.
@@ -693,8 +772,32 @@ public default PrimitiveType primitiveType(final TypeElement e) {
public PrimitiveType primitiveType(final TypeMirror t);
/**
- * Returns a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code null}
- * if there is no such {@link RecordComponentElement}.
+ * A convenience method that returns the raw type corresponding to {@code t}, or {@code null} if
+ * {@code t} is incapable of yielding
+ * a raw type.
+ *
+ * Overrides of this method must conform to the requirements imposed by the relevant section of the relevant + * version of the Java Language Specification concerning raw types.
+ * + * @param t a {@link TypeMirror}; must not be {@code null} + * + * @return the raw type corresponding to the supplied {@link TypeMirror}, or {@code null} if {@code t} is incapable of yielding a raw type + * + * @exception NullPointerException if {@code t} is {@code null} + * + * @spec https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html#jls-4.8 Java Language Specification, section 4.8 + */ + public default TypeMirror rawType(final TypeMirror t) { + return switch (t.getKind()) { + case ARRAY -> this.rawType(this.elementType(t)); // recursive + default -> this.parameterized(t) ? this.erasure(t) : null; + }; + } + + /** + * Returns a {@link RecordComponentElement} corresponding to the supplied {@link ExecutableElement}, or {@code + * null} if there is no such {@link RecordComponentElement}. * * @param e an {@link ExecutableElement} {@linkplain ExecutableElement#getEnclosingElement() enclosed by} a record * representing an accessor method; must not be {@code null} @@ -807,8 +910,8 @@ public default String toString(final CharSequence name) { } /** - * Returns a {@link TypeElement} representing the element bearing the supplied canonical name, or {@code - * null} if there is no such {@link TypeElement}. + * Returns a {@link TypeElement} representing the element bearing the supplied canonical name, or + * {@code null} if there is no such {@link TypeElement}. * * @param canonicalName a valid canonical name; must not be {@code null} * @@ -825,8 +928,8 @@ public default String toString(final CharSequence name) { /** * Returns a {@link TypeElement} representing the element bearing the supplied canonical name, as read or - * seen from the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such {@link - * TypeElement}. + * seen from the module represented by the supplied {@link ModuleElement}, or {@code null} if there is no such + * {@link TypeElement}. * * @param asSeenFrom a {@link ModuleElement}; must not be {@code null} * @@ -922,8 +1025,8 @@ public default TypeElement typeElement(final TypeKind primitiveTypeKind) { /** * Returns the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied * {@link Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain - * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no such {@link - * TypeParameterElement}. + * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no + * such {@link TypeParameterElement}. * * @param p a {@link Parameterizable}; must not be {@code null} * @@ -957,8 +1060,8 @@ public default TypeParameterElement typeParameterElement(Parameterizable p, fina * A convenience method that returns the {@link TypeVariable} {@linkplain TypeParameterElement#asType() declared by} * the {@link TypeParameterElement} {@linkplain Parameterizable#getTypeParameters() contained} by the supplied {@link * Parameterizable} whose {@linkplain TypeParameterElement#getSimpleName() name} {@linkplain - * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no such {@link - * TypeParameterElement} or {@link TypeVariable}. + * Name#contentEquals(CharSequence) is equal to} the supplied {@code name}, or {@code null} if there is no + * such {@link TypeParameterElement} or {@link TypeVariable}. * * @param p a {@link Parameterizable}; must not be {@code null} * @@ -974,10 +1077,10 @@ public default TypeVariable typeVariable(Parameterizable p, final CharSequence n } /** - * A convenience method that returns the first {@link VariableElement} with a {@linkplain - * javax.lang.model.element.ElementKind#isVariable() variableElementKind} and {@linkplain
- * Element#getSimpleName() bearing} the supplied {@code simpleName} that the supplied {@code enclosingElement}
- * {@linkplain Element#getEnclosedElements() encloses}, or {@code null} if there is no such {@link VariableElement}.
+ * A convenience method that returns the first {@link VariableElement} with a {@linkplain ElementKind#isVariable()
+ * variable ElementKind} and {@linkplain Element#getSimpleName() bearing} the supplied {@code simpleName}
+ * that the supplied {@code enclosingElement} {@linkplain Element#getEnclosedElements() encloses}, or {@code
+ * null} if there is no such {@link VariableElement}.
*
* @param enclosingElement an {@link Element}; must not be {@code null}
*
@@ -989,7 +1092,7 @@ public default TypeVariable typeVariable(Parameterizable p, final CharSequence n
*
* @see Element#getEnclosedElements()
*
- * @see javax.lang.model.element.ElementKind#isVariable()
+ * @see ElementKind#isVariable()
*
* @see Element#getSimpleName()
*