diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilder.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilder.java index 457179f9..cdd19154 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilder.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilder.java @@ -1,7 +1,7 @@ package jakarta.enterprise.inject.build.compatible.spi; import jakarta.enterprise.lang.model.AnnotationInfo; -import jakarta.enterprise.lang.model.AnnotationMemberValue; +import jakarta.enterprise.lang.model.AnnotationMember; import jakarta.enterprise.lang.model.declarations.ClassInfo; import jakarta.enterprise.lang.model.types.Type; @@ -45,7 +45,7 @@ static AnnotationBuilder of(ClassInfo annotationType) { * @param value value of the annotation member * @return this {@code AnnotationBuilder} */ - default AnnotationBuilder value(AnnotationMemberValue value) { + default AnnotationBuilder value(AnnotationMember value) { return member(AnnotationInfo.MEMBER_VALUE, value); } @@ -420,7 +420,7 @@ default AnnotationBuilder value(Annotation... values) { * @param value value of the annotation member, must not be {@code null} * @return this {@code AnnotationBuilder} */ - AnnotationBuilder member(String name, AnnotationMemberValue value); + AnnotationBuilder member(String name, AnnotationMember value); /** * Adds a boolean-valued annotation member with given {@code name}. diff --git a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java index 8223170d..c42b9078 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java @@ -4,7 +4,7 @@ import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; -import java.util.Collection; +import java.util.Map; /** * An annotation instance, typically obtained from an {@link AnnotationTarget}. @@ -56,12 +56,12 @@ default boolean isRepeatable() { boolean hasMember(String name); /** - * Returns the {@link AnnotationMemberValue value} of this annotation's member with given {@code name}. + * Returns the {@link AnnotationMember value} of this annotation's member with given {@code name}. * * @param name member name, must not be {@code null} * @return value of this annotation's member with given {@code name} or {@code null} if such member doesn't exist */ - AnnotationMemberValue member(String name); + AnnotationMember member(String name); /** * Returns whether this annotation has the {@link #MEMBER_VALUE value} member. @@ -73,19 +73,19 @@ default boolean hasValue() { } /** - * Returns the {@link AnnotationMemberValue value} of this annotation's {@link #MEMBER_VALUE value} member. + * Returns the {@link AnnotationMember value} of this annotation's {@link #MEMBER_VALUE value} member. * * @return value of this annotation's {@link #MEMBER_VALUE value} member or {@code null} if the member doesn't exist */ - default AnnotationMemberValue value() { + default AnnotationMember value() { return member(MEMBER_VALUE); } /** - * Returns all members of this annotation. Returns an empty collection - * if this annotation has no members. + * Returns all members of this annotation as a map, where the key is the member name + * and the value is the member value. Returns an empty map if this annotation has no members. * - * @return an immutable collection of all members of this annotation, never {@code null} + * @return an immutable map of all members of this annotation, never {@code null} */ - Collection members(); + Map members(); } diff --git a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java index d7222d51..db298bb3 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java @@ -1,24 +1,319 @@ package jakarta.enterprise.lang.model; +import jakarta.enterprise.lang.model.declarations.ClassInfo; +import jakarta.enterprise.lang.model.types.Type; + +import java.util.List; + /** - * An annotation member: name and {@link AnnotationMemberValue value}. + * The value of an annotation member. Annotation member values are of several kinds: + * + * The {@link #kind()} method returns the kind of this annotation member value. + * The {@code is*} methods (such as {@link #isBoolean()}) allow checking + * if this annotation member value is of given kind. The {@code as*} methods + * (such as {@link #asBoolean()} allow "unwrapping" this annotation member value, + * if it is of the corresponding kind. * - * @see #name() - * @see #value() + * TODO do the as* methods allow coercion or not? E.g., does asLong return a long + * if the value is of kind int, or does it throw? Fortunately, this only applies + * to the numeric primitive types and maybe String. I currently left the numeric + * as* methods documented as coercing, while asString as not coercing, but this + * needs more discussion. I personally don't like coercion here and would always + * throw if the type mismatches. */ -// TODO maybe remove this and let AnnotationInfo.members() return Map? public interface AnnotationMember { /** - * Returns the name of this annotation member. + * The kind of the annotation member value. + */ + enum Kind { + /** + * A primitive {@code boolean} value. + */ + BOOLEAN, + /** + * A primitive {@code byte} value. + */ + BYTE, + /** + * A primitive {@code short} value. + */ + SHORT, + /** + * A primitive {@code int} value. + */ + INT, + /** + * A primitive {@code long} value. + */ + LONG, + /** + * A primitive {@code float} value. + */ + FLOAT, + /** + * A primitive {@code double} value. + */ + DOUBLE, + /** + * A primitive {@code char} value. + */ + CHAR, + /** + * A {@link String} value. + */ + STRING, + /** + * An {@link Enum} value. + */ + ENUM, + /** + * A {@link Class} value. Represented as {@link Type}. + */ + CLASS, + /** + * A nested {@link java.lang.annotation.Annotation Annotation} value. + * Represented as {@link AnnotationInfo}. + */ + NESTED_ANNOTATION, + /** + * An array value. + */ + ARRAY, + } + + /** + * Returns the kind of this annotation member value. + * + * @return the kind of this annotation member value, never {@code null} + */ + Kind kind(); + + /** + * @return {@code true} if the kind is a {@code boolean}, {@code false} otherwise + */ + default boolean isBoolean() { + return kind() == Kind.BOOLEAN; + } + + /** + * @return {@code true} if the kind is a {@code byte}, {@code false} otherwise + */ + default boolean isByte() { + return kind() == Kind.BYTE; + } + + /** + * @return {@code true} if the kind is a {@code short}, {@code false} otherwise + */ + default boolean isShort() { + return kind() == Kind.SHORT; + } + + /** + * @return {@code true} if the kind is an {@code int}, {@code false} otherwise + */ + default boolean isInt() { + return kind() == Kind.INT; + } + + /** + * @return {@code true} if the kind is a {@code long}, {@code false} otherwise + */ + default boolean isLong() { + return kind() == Kind.LONG; + } + + /** + * @return {@code true} if the kind is a {@code float}, {@code false} otherwise + */ + default boolean isFloat() { + return kind() == Kind.FLOAT; + } + + /** + * @return {@code true} if the kind is a {@code double}, {@code false} otherwise + */ + default boolean isDouble() { + return kind() == Kind.DOUBLE; + } + + /** + * @return {@code true} if the kind is a {@code char}, {@code false} otherwise + */ + default boolean isChar() { + return kind() == Kind.CHAR; + } + + /** + * @return {@code true} if the kind is a {@link String}, {@code false} otherwise + */ + default boolean isString() { + return kind() == Kind.STRING; + } + + /** + * @return {@code true} if the kind is an {@link Enum}, {@code false} otherwise + */ + default boolean isEnum() { + return kind() == Kind.ENUM; + } + + /** + * @return {@code true} if the kind is a {@link Class}, {@code false} otherwise + */ + default boolean isClass() { + return kind() == Kind.CLASS; + } + + /** + * @return {@code true} if the kind is a nested {@link java.lang.annotation.Annotation Annotation}, {@code false} otherwise + */ + default boolean isNestedAnnotation() { + return kind() == Kind.NESTED_ANNOTATION; + } + + /** + * @return {@code true} if the kind is an array, {@code false} otherwise + */ + default boolean isArray() { + return kind() == Kind.ARRAY; + } + + /** + * Returns this value as a boolean. + * + * @return the boolean value + * @throws IllegalStateException if this annotation member value is not a boolean + */ + boolean asBoolean(); + + /** + * Returns this value as a byte. + * + * @return the byte value + * @throws IllegalStateException if the value cannot be represented as a byte + */ + byte asByte(); + + /** + * Returns this value as a short. + * + * @return the short value + * @throws IllegalStateException if the value cannot be represented as a short. + */ + short asShort(); + + /** + * Returns this value as an int. + * + * @return the int value + * @throws IllegalStateException if the value cannot be represented as an int. + */ + int asInt(); + + /** + * Returns this value as a long. + * + * @return the long value + * @throws IllegalStateException if the value cannot be represented as a long. + */ + long asLong(); + + /** + * Returns this value as a float. + * + * @return the float value + * @throws IllegalStateException if the value cannot be represented as a float. + */ + float asFloat(); + + /** + * Returns this value as a double. + * + * @return the double value + * @throws IllegalStateException if the value cannot be represented as a double. + */ + double asDouble(); + + /** + * Returns this value as a char. + * + * @return the char value + * @throws IllegalStateException if this annotation member value is not a char + */ + char asChar(); + + /** + * Returns this value as a String. + * + * @return the String value + * @throws IllegalStateException if this annotation member value is not a String + */ + String asString(); + + /** + * Returns this enum value as an instance of the enum type. + * + * @param enumType the enum type + * @param the enum generic type + * @return the enum instance + * @throws IllegalArgumentException if given {@code enumType} is not an enum type + * @throws IllegalStateException if this annotation member value is not an enum value + */ + > E asEnum(Class enumType); + + /** + * Returns the type of this enum value. + * + * @return a {@link ClassInfo} representing the enum type + * @throws IllegalStateException if this annotation member value is not an enum value + */ + ClassInfo asEnumClass(); + + /** + * Returns the name (also known as enum constant) of this enum value. + * + * @return the enum constant + * @throws IllegalStateException if this annotation member value is not an enum value + */ + String asEnumConstant(); + + /** + * Returns this class value as a {@link Type}. It can possibly be: + *
    + *
  • the {@link jakarta.enterprise.lang.model.types.VoidType void} type;
  • + *
  • a {@link jakarta.enterprise.lang.model.types.PrimitiveType primitive} type;
  • + *
  • a {@link jakarta.enterprise.lang.model.types.ClassType class} type;
  • + *
  • an {@link jakarta.enterprise.lang.model.types.ArrayType array} type, whose component type + * is a primitive type or a class type.
  • + *
+ * + * @return the class value, as a {@link Type} + * @throws IllegalStateException if this annotation member value is not a class value + */ + Type asType(); + + /** + * Returns this nested annotation value as an {@link AnnotationInfo}. * - * @return the name of this annotation member, never {@code null} + * @return an {@link AnnotationInfo} instance + * @throws IllegalStateException if this annotation member value is not a nested annotation */ - String name(); + AnnotationInfo asNestedAnnotation(); /** - * Returns the {@link AnnotationMemberValue value} of this annotation member. + * Returns this array value as an immutable {@link List} of {@link AnnotationMember}s. + * Returns an empty list if the array is empty. * - * @return the value of this annotation member, never {@code null} + * @return an immutable list of {@link AnnotationMember}s + * @throws IllegalStateException if this annotation member value is not an array */ - AnnotationMemberValue value(); + List asArray(); } diff --git a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java deleted file mode 100644 index 8afc19f3..00000000 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java +++ /dev/null @@ -1,320 +0,0 @@ -package jakarta.enterprise.lang.model; - -import jakarta.enterprise.lang.model.declarations.ClassInfo; -import jakarta.enterprise.lang.model.types.Type; - -import java.util.List; - -/** - * The value of an {@link AnnotationMember}. Annotation member values are of several kinds: - *
    - *
  • primitive types;
  • - *
  • {@link String}s;
  • - *
  • {@link Enum}s;
  • - *
  • {@link Class}es;
  • - *
  • nested {@link java.lang.annotation.Annotation Annotation}s;
  • - *
  • arrays of previously mentioned types.
  • - *
- * The {@link #kind()} method returns the kind of this annotation member value. - * The {@code is*} methods (such as {@link #isBoolean()}) allow checking - * if this annotation member value is of given kind. The {@code as*} methods - * (such as {@link #asBoolean()} allow "unwrapping" this annotation member value, - * if it is of the corresponding kind. - * - * TODO do the as* methods allow coercion or not? E.g., does asLong return a long - * if the value is of kind int, or does it throw? Fortunately, this only applies - * to the numeric primitive types and maybe String. I currently left the numeric - * as* methods documented as coercing, while asString as not coercing, but this - * needs more discussion. I personally don't like coercion here and would always - * throw if the type mismatches. - */ -public interface AnnotationMemberValue { - /** - * The kind of the annotation member value. - */ - enum Kind { - /** - * A primitive {@code boolean}. - */ - BOOLEAN, - /** - * A primitive {@code byte}. - */ - BYTE, - /** - * A primitive {@code short}. - */ - SHORT, - /** - * A primitive {@code int}. - */ - INT, - /** - * A primitive {@code long}. - */ - LONG, - /** - * A primitive {@code float}. - */ - FLOAT, - /** - * A primitive {@code double}. - */ - DOUBLE, - /** - * A primitive {@code char}. - */ - CHAR, - /** - * A {@link String} value. - */ - STRING, - /** - * An {@link Enum} value. - */ - ENUM, - /** - * A {@link Class} value. Represented as {@link jakarta.enterprise.lang.model.types.Type}. - */ - CLASS, - /** - * A nested {@link java.lang.annotation.Annotation Annotation} value. - * Represented as {@link AnnotationInfo}. - */ - NESTED_ANNOTATION, - /** - * An array value. - */ - ARRAY, - } - - /** - * Returns the kind of the annotation member value. - * - * @return the kind of the annotation member value, never {@code null} - */ - Kind kind(); - - /** - * @return {@code true} if the kind is a {@code boolean}, {@code false} otherwise - */ - default boolean isBoolean() { - return kind() == Kind.BOOLEAN; - } - - /** - * @return {@code true} if the kind is a {@code byte}, {@code false} otherwise - */ - default boolean isByte() { - return kind() == Kind.BYTE; - } - - /** - * @return {@code true} if the kind is a {@code short}, {@code false} otherwise - */ - default boolean isShort() { - return kind() == Kind.SHORT; - } - - /** - * @return {@code true} if the kind is an {@code int}, {@code false} otherwise - */ - default boolean isInt() { - return kind() == Kind.INT; - } - - /** - * @return {@code true} if the kind is a {@code long}, {@code false} otherwise - */ - default boolean isLong() { - return kind() == Kind.LONG; - } - - /** - * @return {@code true} if the kind is a {@code float}, {@code false} otherwise - */ - default boolean isFloat() { - return kind() == Kind.FLOAT; - } - - /** - * @return {@code true} if the kind is a {@code double}, {@code false} otherwise - */ - default boolean isDouble() { - return kind() == Kind.DOUBLE; - } - - /** - * @return {@code true} if the kind is a {@code char}, {@code false} otherwise - */ - default boolean isChar() { - return kind() == Kind.CHAR; - } - - /** - * @return {@code true} if the kind is a {@link String}, {@code false} otherwise - */ - default boolean isString() { - return kind() == Kind.STRING; - } - - /** - * @return {@code true} if the kind is an {@link Enum}, {@code false} otherwise - */ - default boolean isEnum() { - return kind() == Kind.ENUM; - } - - /** - * @return {@code true} if the kind is a {@link Class}, {@code false} otherwise - */ - default boolean isClass() { - return kind() == Kind.CLASS; - } - - /** - * @return {@code true} if the kind is a nested {@link java.lang.annotation.Annotation Annotation}, {@code false} otherwise - */ - default boolean isNestedAnnotation() { - return kind() == Kind.NESTED_ANNOTATION; - } - - /** - * @return {@code true} if the kind is an array, {@code false} otherwise - */ - default boolean isArray() { - return kind() == Kind.ARRAY; - } - - /** - * Returns the value as a boolean. - * - * @return the boolean value - * @throws IllegalStateException if this annotation member value is not a boolean - */ - boolean asBoolean(); - - /** - * Returns the value as a byte. - * - * @return the byte value - * @throws IllegalStateException if the value cannot be represented as a byte - */ - byte asByte(); - - /** - * Returns the value as a short. - * - * @return the short value - * @throws IllegalStateException if the value cannot be represented as a short. - */ - short asShort(); - - /** - * Returns the value as an int. - * - * @return the int value - * @throws IllegalStateException if the value cannot be represented as an int. - */ - int asInt(); - - /** - * Returns the value as a long. - * - * @return the long value - * @throws IllegalStateException if the value cannot be represented as a long. - */ - long asLong(); - - /** - * Returns the value as a float. - * - * @return the float value - * @throws IllegalStateException if the value cannot be represented as a float. - */ - float asFloat(); - - /** - * Returns the value as a double. - * - * @return the double value - * @throws IllegalStateException if the value cannot be represented as a double. - */ - double asDouble(); - - /** - * Returns the value as a char. - * - * @return the char value - * @throws IllegalStateException if this annotation member value is not a char - */ - char asChar(); - - /** - * Returns the value as a String. - * - * @return the String value - * @throws IllegalStateException if this annotation member value is not a String - */ - String asString(); - - /** - * Returns the value as an enum instance. - * - * @param enumType the enum type - * @param the enum generic type - * @return the enum instance - * @throws IllegalArgumentException if given {@code enumType} is not an enum type - * @throws IllegalStateException if this annotation member value is not an enum value - */ - // TODO we should be able to remove the Class parameter - > E asEnum(Class enumType); - - /** - * Returns the enum type of the annotation member value. - * - * @return a {@link ClassInfo} representing the enum type - * @throws IllegalStateException if this annotation member value is not an enum value - */ - ClassInfo asEnumClass(); - - /** - * Returns the enum constant of the annotation member value. - * - * @return the enum constant - * @throws IllegalStateException if this annotation member value is not an enum value - */ - String asEnumConstant(); - - /** - * Returns the class value, represented as a {@link Type}. It can possibly be: - *
    - *
  • the {@link jakarta.enterprise.lang.model.types.VoidType void} type;
  • - *
  • a {@link jakarta.enterprise.lang.model.types.PrimitiveType primitive} type;
  • - *
  • a {@link jakarta.enterprise.lang.model.types.ClassType class} type;
  • - *
  • an {@link jakarta.enterprise.lang.model.types.ArrayType array} type, whose component type - * is one of the previously mentioned types.
  • - *
- * - * @return the class value, as a {@link Type} - * @throws IllegalStateException if this annotation member value is not a class value - */ - Type asType(); - - /** - * Returns the nested annotation value as an {@link AnnotationInfo}. - * - * @return an {@link AnnotationInfo} instance - * @throws IllegalStateException if this annotation member value is not a nested annotation - */ - AnnotationInfo asNestedAnnotation(); - - /** - * Returns the array value as an immutable {@link List} of {@link AnnotationMemberValue}s. - * Returns an empty list if the array value is an empty array. - * - * @return an immutable list of {@link AnnotationMemberValue}s - * @throws IllegalStateException if this annotation member value is not an array - */ - List asArray(); -}