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 new file mode 100644 index 00000000..457179f9 --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilder.java @@ -0,0 +1,763 @@ +package jakarta.enterprise.inject.build.compatible.spi; + +import jakarta.enterprise.lang.model.AnnotationInfo; +import jakarta.enterprise.lang.model.AnnotationMemberValue; +import jakarta.enterprise.lang.model.declarations.ClassInfo; +import jakarta.enterprise.lang.model.types.Type; + +import java.lang.annotation.Annotation; + +/** + * Builder for annotations of given type. + * Expected usage is: + *
    + *
  1. create the builder using {@link #of(Class)} or {@link #of(ClassInfo)};
  2. + *
  3. use the {@code value()} and {@code member()} methods to define annotation members;
  4. + *
  5. call {@link #build()} to create an {@link AnnotationInfo}.
  6. + *
+ * One builder instance should not be used to create multiple annotations. + */ +// TODO not sure if all the methods taking ClassInfo are needed, maybe they're not +public interface AnnotationBuilder { + /** + * Returns a new {@link AnnotationBuilder} that builds an annotation of given type. + * + * @param annotationType the annotation type, must not be {@code null} + * @return a new {@code AnnotationBuilder}, never {@code null} + */ + static AnnotationBuilder of(Class annotationType) { + return AnnotationBuilderFactoryResolver.get().create(annotationType); + } + + /** + * Returns a new {@link AnnotationBuilder} that builds an annotation of given type. + * + * @param annotationType the annotation type, must not be {@code null} + * @return a new {@code AnnotationBuilder} + */ + static AnnotationBuilder of(ClassInfo annotationType) { + return AnnotationBuilderFactoryResolver.get().create(annotationType); + } + + /** + * Adds an annotation member called {@code value}, whose value is given {@code value}. + * + * @param value value of the annotation member + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(AnnotationMemberValue value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a boolean-valued annotation member called {@code value}. + * + * @param value the boolean value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(boolean value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a boolean array-valued annotation member called {@code value}. + * + * @param values the boolean array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(boolean... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a byte-valued annotation member called {@code value}. + * + * @param value the byte value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(byte value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a byte array-valued annotation member called {@code value}. + * + * @param values the byte array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(byte... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a short-valued annotation member called {@code value}. + * + * @param value the short value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(short value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a short array-valued annotation member called {@code value}. + * + * @param values the short array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(short... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an int-valued annotation member called {@code value}. + * + * @param value the int value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(int value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds an int array-valued annotation member called {@code value}. + * + * @param values the int array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(int... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a long-valued annotation member called {@code value}. + * + * @param value the long value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(long value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a long array-valued annotation member called {@code value}. + * + * @param values the long array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(long... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a float-valued annotation member called {@code value}. + * + * @param value the float value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(float value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a float array-valued annotation member called {@code value}. + * + * @param values the float array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(float... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a double-valued annotation member called {@code value}. + * + * @param value the double value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(double value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a double array-valued annotation member called {@code value}. + * + * @param values the double array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(double... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a char-valued annotation member called {@code value}. + * + * @param value the char value + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(char value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a char array-valued annotation member called {@code value}. + * + * @param values the char array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(char... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a String-valued annotation member called {@code value}. + * + * @param value the String value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(String value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a String array-valued annotation member called {@code value}. + * + * @param values the String array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(String... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an enum-valued annotation member called {@code value}. + * + * @param value the enum value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Enum value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds an enum array-valued annotation member called {@code value}. + * + * @param values the enum array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Enum... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an enum-valued annotation member called {@code value}. + * + * @param enumType the enum type, must not be {@code null} + * @param enumValue name of the enum constant, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Class> enumType, String enumValue) { + return member(AnnotationInfo.MEMBER_VALUE, enumType, enumValue); + } + + /** + * Adds an enum array-valued annotation member called {@code value}. + * + * @param enumType the enum type, must not be {@code null} + * @param enumValues names of the enum constants, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Class> enumType, String... enumValues) { + return member(AnnotationInfo.MEMBER_VALUE, enumType, enumValues); + } + + /** + * Adds an enum-valued annotation member called {@code value}. + * + * @param enumType the enum type, must not be {@code null} + * @param enumValue name of the enum constant, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(ClassInfo enumType, String enumValue) { + return member(AnnotationInfo.MEMBER_VALUE, enumType, enumValue); + } + + /** + * Adds an enum array-valued annotation member called {@code value}. + * + * @param enumType the enum type, must not be {@code null} + * @param enumValues names of the enum constants, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(ClassInfo enumType, String... enumValues) { + return member(AnnotationInfo.MEMBER_VALUE, enumType, enumValues); + } + + /** + * Adds a class-valued annotation member called {@code value}. + * + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Class value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a class array-valued annotation member called {@code value}. + * + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Class... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a class-valued annotation member called {@code value}. + * + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(ClassInfo value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a class array-valued annotation member called {@code value}. + * + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(ClassInfo... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds a class-valued annotation member called {@code value}. + * The {@code value} parameter may only be: + * + * + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + * @throws IllegalArgumentException if given type is invalid, as described above + */ + default AnnotationBuilder value(Type value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds a class array-valued annotation member called {@code value}. + * The {@code values} parameter may only contain: + * + * + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + * @throws IllegalArgumentException if any given type is invalid, as described above + */ + default AnnotationBuilder value(Type... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an annotation-valued annotation member called {@code value}. + * + * @param value the annotation value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(AnnotationInfo value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds an annotation array-valued annotation member called {@code value}. + * + * @param values the annotation array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(AnnotationInfo... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an annotation-valued annotation member called {@code value}. + * + * @param value the annotation value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Annotation value) { + return member(AnnotationInfo.MEMBER_VALUE, value); + } + + /** + * Adds an annotation array-valued annotation member called {@code value}. + * + * @param values the annotation array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + default AnnotationBuilder value(Annotation... values) { + return member(AnnotationInfo.MEMBER_VALUE, values); + } + + /** + * Adds an annotation member with given {@code name}, whose value is given {@code value}. + * + * @param name name of the annotation member, must not be {@code null} + * @param value value of the annotation member, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, AnnotationMemberValue value); + + /** + * Adds a boolean-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the boolean value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, boolean value); + + /** + * Adds a boolean array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the boolean array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, boolean... values); + + /** + * Adds a byte-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the byte value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, byte value); + + /** + * Adds a byte array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the byte array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, byte... values); + + /** + * Adds a short-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the short value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, short value); + + /** + * Adds a short array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the short array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, short... values); + + /** + * Adds an int-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the int value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, int value); + + /** + * Adds an int array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the int array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, int... values); + + /** + * Adds a long-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the long value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, long value); + + /** + * Adds a long array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the long array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, long... values); + + /** + * Adds a float-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the float value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, float value); + + /** + * Adds a float array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the float array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, float... values); + + /** + * Adds a double-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the double value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, double value); + + /** + * Adds a double array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the double array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, double... values); + + /** + * Adds a char-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the char value + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, char value); + + /** + * Adds a char array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the char array, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, char... values); + + /** + * Adds a String-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the String value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, String value); + + /** + * Adds a String array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the String array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, String... values); + + /** + * Adds an enum-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the enum value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Enum value); + + /** + * Adds an enum array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the enum array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Enum... values); + + /** + * Adds an enum-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param enumType the enum type, must not be {@code null} + * @param enumValue name of the enum constant, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Class> enumType, String enumValue); + + /** + * Adds an enum array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param enumType the enum type, must not be {@code null} + * @param enumValues names of the enum constants, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Class> enumType, String... enumValues); + + /** + * Adds an enum-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param enumType the enum type, must not be {@code null} + * @param enumValue name of the enum constant, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, ClassInfo enumType, String enumValue); + + /** + * Adds an enum array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param enumType the enum type, must not be {@code null} + * @param enumValues names of the enum constants, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, ClassInfo enumType, String... enumValues); + + /** + * Adds a class-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Class value); + + /** + * Adds a class array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Class... values); + + /** + * Adds a class-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, ClassInfo value); + + /** + * Adds a class array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, ClassInfo... values); + + /** + * Adds a class-valued annotation member with given {@code name}. + * The {@code value} parameter may only be: + * + * Any other value results in an exception. + * + * @param name the member name, must not be {@code null} + * @param value the class value, must not be {@code null} + * @return this {@code AnnotationBuilder} + * @throws IllegalArgumentException if given type is invalid, as described above + */ + AnnotationBuilder member(String name, Type value); + + /** + * Adds a class array-valued annotation member with given {@code name}. + * The {@code values} parameter may only include: + * + * + * @param name the member name, must not be {@code null} + * @param values the class array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + * @throws IllegalArgumentException if any given type is invalid, as described above + */ + AnnotationBuilder member(String name, Type... values); + + /** + * Adds an annotation-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the annotation value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, AnnotationInfo value); + + /** + * Adds an annotation array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the annotation array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, AnnotationInfo... values); + + /** + * Adds an annotation-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param value the annotation value, must not be {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Annotation value); + + /** + * Adds an annotation array-valued annotation member with given {@code name}. + * + * @param name the member name, must not be {@code null} + * @param values the annotation array, must not be {@code null} or contain {@code null} + * @return this {@code AnnotationBuilder} + */ + AnnotationBuilder member(String name, Annotation... values); + + /** + * Returns an {@link AnnotationInfo} that includes all annotation members defined by previous method calls + * on this builder. After {@code build()} is called, this builder instance should be discarded. + * + * @return the built {@link AnnotationInfo}, never {@code null} + */ + AnnotationInfo build(); +} diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactory.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactory.java new file mode 100644 index 00000000..6dc7fdf2 --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactory.java @@ -0,0 +1,28 @@ +package jakarta.enterprise.inject.build.compatible.spi; + +import jakarta.enterprise.inject.spi.Prioritized; +import jakarta.enterprise.lang.model.declarations.ClassInfo; + +import java.lang.annotation.Annotation; + +/** + * Service provider interface that supports creating {@link AnnotationBuilder}. + * Should not be called directly by users; the static methods on {@link AnnotationBuilder} are preferred. + */ +public interface AnnotationBuilderFactory extends Prioritized { + /** + * Returns a new {@link AnnotationBuilder} for given annotation type. + * + * @param annotationType the annotation type + * @return a new {@link AnnotationBuilder} + */ + AnnotationBuilder create(Class annotationType); + + /** + * Returns a new {@link AnnotationBuilder} for given annotation type. + * + * @param annotationType the annotation type + * @return a new {@link AnnotationBuilder} + */ + AnnotationBuilder create(ClassInfo annotationType); +} diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactoryResolver.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactoryResolver.java new file mode 100644 index 00000000..6a55ebda --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationBuilderFactoryResolver.java @@ -0,0 +1,54 @@ +package jakarta.enterprise.inject.build.compatible.spi; + +import java.util.Collections; +import java.util.Comparator; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.TreeSet; + +final class AnnotationBuilderFactoryResolver { + private static final Object lock = new Object(); + private static volatile Set discoveredFactories; + private static volatile AnnotationBuilderFactory configuredFactory; + + static AnnotationBuilderFactory get() { + if (configuredFactory != null) { + return configuredFactory; + } + + if (discoveredFactories == null) { + synchronized (lock) { + if (discoveredFactories == null) { + discoverFactories(); + } + } + } + + configuredFactory = discoveredFactories.iterator().next(); + + return configuredFactory; + } + + private static void discoverFactories() { + Set factories = new TreeSet<>( + Comparator.comparingInt(AnnotationBuilderFactory::getPriority).reversed()); + + ServiceLoader loader = SecurityActions.loadService( + AnnotationBuilderFactory.class, AnnotationBuilderFactoryResolver.class.getClassLoader()); + + if (!loader.iterator().hasNext()) { + throw new IllegalStateException("Unable to locate AnnotationBuilderFactory implementation"); + } + + try { + for (AnnotationBuilderFactory factory : loader) { + factories.add(factory); + } + } catch (ServiceConfigurationError e) { + throw new IllegalStateException(e); + } + + AnnotationBuilderFactoryResolver.discoveredFactories = Collections.unmodifiableSet(factories); + } +} diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationConfig.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationConfig.java index 92fa33c2..da78fb9e 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationConfig.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/AnnotationConfig.java @@ -1,17 +1,13 @@ package jakarta.enterprise.inject.build.compatible.spi; -import jakarta.enterprise.lang.model.AnnotationMember; import jakarta.enterprise.lang.model.AnnotationInfo; -import jakarta.enterprise.lang.model.declarations.ClassInfo; + import java.lang.annotation.Annotation; import java.util.function.Predicate; // TODO better name? -// TODO devise a builder-style API instead (see also Annotations) public interface AnnotationConfig { - void addAnnotation(Class annotationType, AnnotationMember... attributes); - - void addAnnotation(ClassInfo annotationType, AnnotationMember... attributes); + void addAnnotation(Class annotationType); // for marker annotations void addAnnotation(AnnotationInfo annotation); diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Annotations.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Annotations.java deleted file mode 100644 index 261aef18..00000000 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Annotations.java +++ /dev/null @@ -1,84 +0,0 @@ -package jakarta.enterprise.inject.build.compatible.spi; - -import jakarta.enterprise.lang.model.AnnotationMember; -import jakarta.enterprise.lang.model.AnnotationMemberValue; -import jakarta.enterprise.lang.model.AnnotationInfo; -import jakarta.enterprise.lang.model.declarations.ClassInfo; -import java.lang.annotation.Annotation; -import java.util.List; - -// TODO devise a builder-style API instead (see also AnnotationConfig) -public interface Annotations { - AnnotationMemberValue value(boolean value); - - AnnotationMemberValue value(byte value); - - AnnotationMemberValue value(short value); - - AnnotationMemberValue value(int value); - - AnnotationMemberValue value(long value); - - AnnotationMemberValue value(float value); - - AnnotationMemberValue value(double value); - - AnnotationMemberValue value(char value); - - AnnotationMemberValue value(String value); - - AnnotationMemberValue value(Enum enumValue); - - AnnotationMemberValue value(Class> enumType, String enumValue); - - AnnotationMemberValue value(ClassInfo enumType, String enumValue); - - AnnotationMemberValue value(Class value); - - AnnotationMemberValue annotationValue(Class annotationType, AnnotationMember... attributes); - - AnnotationMemberValue annotationValue(ClassInfo annotationType, AnnotationMember... attributes); - - AnnotationMemberValue annotationValue(AnnotationInfo annotation); - - AnnotationMemberValue annotationValue(Annotation annotation); - - AnnotationMember attribute(String name, boolean value); - - AnnotationMember attribute(String name, byte value); - - AnnotationMember attribute(String name, short value); - - AnnotationMember attribute(String name, int value); - - AnnotationMember attribute(String name, long value); - - AnnotationMember attribute(String name, float value); - - AnnotationMember attribute(String name, double value); - - AnnotationMember attribute(String name, char value); - - AnnotationMember attribute(String name, String value); - - AnnotationMember attribute(String name, Enum enumValue); - - AnnotationMember attribute(String name, Class> enumType, String enumValue); - - AnnotationMember attribute(String name, ClassInfo enumType, String enumValue); - - AnnotationMember attribute(String name, Class value); - - AnnotationMember arrayAttribute(String name, AnnotationMemberValue... values); - - AnnotationMember arrayAttribute(String name, List values); - - AnnotationMember annotationAttribute(String name, Class annotationType, - AnnotationMember... attributes); - - AnnotationMember annotationAttribute(String name, ClassInfo annotationType, AnnotationMember... attributes); - - AnnotationMember annotationAttribute(String name, AnnotationInfo annotation); - - AnnotationMember annotationAttribute(String name, Annotation annotation); -} diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Enhancement.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Enhancement.java index 6db80628..787eff0b 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Enhancement.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/Enhancement.java @@ -20,12 +20,11 @@ * You can also declare a parameter of type {@link Messages Messages} to produce log messages and validation errors. *

* If you need to create instances of {@link jakarta.enterprise.lang.model.types.Type Type}, you can also declare - * a parameter of type {@link Types Types}. It provides factory methods for the void type, primitive types, + * a parameter of type {@link Types}. It provides factory methods for the void type, primitive types, * class types, array types, parameterized types and wildcard types. *

- * If you need to create instances of {@link jakarta.enterprise.lang.model.AnnotationMember AnnotationAttribute} or - * {@link jakarta.enterprise.lang.model.AnnotationMemberValue AnnotationAttributeValue}, you can also declare - * a parameter of type {@link Annotations Annotations}. It provides factory methods for all kinds of annotation attributes. + * If you need to create instances of {@link jakarta.enterprise.lang.model.AnnotationInfo AnnotationInfo}, + * use {@link AnnotationBuilder}. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/MetaAnnotations.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/MetaAnnotations.java index 10fed9fc..2f677156 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/MetaAnnotations.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/MetaAnnotations.java @@ -45,6 +45,8 @@ public interface MetaAnnotations { /** * Registers custom context as configured by the returned {@link ContextConfig}. + * + * @return custom context configurator, never {@code null} */ ContextConfig addContext(); } diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/ScopeInfo.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/ScopeInfo.java index 45c07317..b0a88c06 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/ScopeInfo.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/ScopeInfo.java @@ -4,14 +4,18 @@ public interface ScopeInfo { /** - * @return declaration of the scope annotation + * Returns the declaration of this scope annotation's type. + * + * @return declaration of this scope annotation's type, never {@code null} */ ClassInfo annotation(); /** + * Binary name of this scope annotation's type, as defined by The Java™ Language Specification; + * in other words, the scope annotation type name as returned by {@link Class#getName()}. * Equivalent to {@code annotation().name()}. * - * @return fully qualified name of the annotation + * @return binary name of this scope annotation's type, never {@code null} */ default String name() { return annotation().name(); @@ -19,7 +23,7 @@ default String name() { /** * Returns whether the scope is normal. In other words, returns whether - * the scope annotation type is meta-annotated with {@code @NormalScope}. + * the scope annotation type is meta-annotated {@code @NormalScope}. * * @return whether the scope is normal */ diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SecurityActions.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SecurityActions.java new file mode 100644 index 00000000..d7fd5135 --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SecurityActions.java @@ -0,0 +1,39 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2018, Red Hat, Inc., and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * Licensed under the Apache License, Version 2.1-SNAPSHOT (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.1-SNAPSHOT + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jakarta.enterprise.inject.build.compatible.spi; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ServiceLoader; + +/** + * This utility class is used to optimize invocation made through the SecurityManager + * + * @author Antoine Sabot-durand + */ + +final class SecurityActions { + private SecurityActions() { + } + + static ServiceLoader loadService(Class service, ClassLoader classLoader) { + return AccessController.doPrivileged( + (PrivilegedAction>) () -> ServiceLoader.load(service, classLoader) + ); + } +} diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticBeanBuilder.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticBeanBuilder.java index 43e49e02..148b27c6 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticBeanBuilder.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticBeanBuilder.java @@ -1,9 +1,9 @@ package jakarta.enterprise.inject.build.compatible.spi; -import jakarta.enterprise.lang.model.AnnotationMember; import jakarta.enterprise.lang.model.AnnotationInfo; import jakarta.enterprise.lang.model.declarations.ClassInfo; import jakarta.enterprise.lang.model.types.Type; + import java.lang.annotation.Annotation; /** @@ -25,11 +25,9 @@ public interface SyntheticBeanBuilder { // can be called multiple times and is additive // TODO methods to add multiple qualifiers at once? - SyntheticBeanBuilder qualifier(Class qualifierAnnotation, AnnotationMember... attributes); - - SyntheticBeanBuilder qualifier(ClassInfo qualifierAnnotation, AnnotationMember... attributes); + SyntheticBeanBuilder qualifier(Class annotationType); // for marker annotations - SyntheticBeanBuilder qualifier(AnnotationInfo qualifierAnnotation); + SyntheticBeanBuilder qualifier(AnnotationInfo qualifierAnnotation); SyntheticBeanBuilder qualifier(Annotation qualifierAnnotation); diff --git a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticObserverBuilder.java b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticObserverBuilder.java index 3f94c152..8aeacbad 100644 --- a/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticObserverBuilder.java +++ b/api/src/main/java/jakarta/enterprise/inject/build/compatible/spi/SyntheticObserverBuilder.java @@ -1,12 +1,12 @@ package jakarta.enterprise.inject.build.compatible.spi; -import jakarta.enterprise.lang.model.AnnotationMember; +import jakarta.enterprise.event.Reception; +import jakarta.enterprise.event.TransactionPhase; import jakarta.enterprise.lang.model.AnnotationInfo; import jakarta.enterprise.lang.model.declarations.ClassInfo; import jakarta.enterprise.lang.model.types.Type; + import java.lang.annotation.Annotation; -import jakarta.enterprise.event.Reception; -import jakarta.enterprise.event.TransactionPhase; /** * Instances are not reusable. For each synthetic observer, new instance @@ -40,11 +40,9 @@ public interface SyntheticObserverBuilder { // can be called multiple times and is additive // TODO methods to add multiple qualifiers at once? - SyntheticObserverBuilder qualifier(Class qualifierAnnotation, AnnotationMember... attributes); - - SyntheticObserverBuilder qualifier(ClassInfo qualifierAnnotation, AnnotationMember... attributes); + SyntheticObserverBuilder qualifier(Class annotationType); // for marker annotations - SyntheticObserverBuilder qualifier(AnnotationInfo qualifierAnnotation); + SyntheticObserverBuilder qualifier(AnnotationInfo qualifierAnnotation); SyntheticObserverBuilder qualifier(Annotation qualifierAnnotation); 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 e0a5d565..8223170d 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationInfo.java @@ -7,29 +7,31 @@ import java.util.Collection; /** - * Models an annotation definition, providing access to the {@link AnnotationMemberValue} - * instances. + * An annotation instance, typically obtained from an {@link AnnotationTarget}. + * Provides access to annotation members and their values. * - * @param The annotation type. + * @param the annotation type */ +// TODO does this have to be parameterized? public interface AnnotationInfo { /** - * The commonly used {@code value()} member. + * Name of the commonly used {@code value()} annotation member. */ String MEMBER_VALUE = "value"; /** * Declaration of this annotation's type. * - * @return declaration of this annotation, never {@code null} + * @return declaration of this annotation's type, never {@code null} */ ClassInfo declaration(); /** - * Fully qualified name of this annotation. + * Binary name of this annotation's type, as defined by The Java™ Language Specification; + * in other words, the annotation type name as returned by {@link Class#getName()}. * Equivalent to {@code declaration().name()}. * - * @return fully qualified name of this annotation, never {@code null} + * @return binary name of this annotation's type, never {@code null} */ default String name() { return declaration().name(); @@ -37,7 +39,7 @@ default String name() { /** * Returns whether this annotation is repeatable. In other words, returns whether - * this annotation's type is meta-annotated with {@code @Repeatable}. + * this annotation's type is meta-annotated {@code @Repeatable}. * * @return whether this annotation is repeatable */ @@ -46,45 +48,44 @@ default boolean isRepeatable() { } /** - * Whether this annotation has a member with given {@code name}. + * Returns whether this annotation has a member with given {@code name}. * - * @param name member name, never {@code null} - * @return whether this annotation has a member with given {@code name} - * @throws java.lang.NullPointerException if the argument is {@code null} + * @param name member name, must not be {@code null} + * @return {@code true} if this annotation has a member with given {@code name}, {@code false} otherwise */ boolean hasMember(String name); /** - * Value of this annotation's attribute with given {@code name}. + * Returns the {@link AnnotationMemberValue value} of this annotation's member with given {@code name}. * - * @param name attribute name, never {@code null} - * @return value of this annotation's attribute with given {@code name} or {@code null} if it doesn't exist. - * @throws java.lang.NullPointerException if the argument is {@code null} + * @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); /** - * Returns whether this annotation has the {@link #MEMBER_VALUE} member. + * Returns whether this annotation has the {@link #MEMBER_VALUE value} member. * - * @return Returns {@code true} if the {@link #MEMBER_VALUE} is set, {@code false} otherwise + * @return {@code true} if this annotation has the {@link #MEMBER_VALUE value} member, {@code false} otherwise */ default boolean hasValue() { return hasMember(MEMBER_VALUE); } /** - * Returns the {@link AnnotationMemberValue} instance that represents - * the value of the {@link #MEMBER_VALUE} member. - * @return An {@link AnnotationMemberValue} instance or {@code null} if none exists. + * Returns the {@link AnnotationMemberValue 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() { return member(MEMBER_VALUE); } /** - * All members of this annotation. + * Returns all members of this annotation. Returns an empty collection + * if this annotation has no members. * - * @return An immutable collection of all members of this annotation. Never {@code null}. + * @return an immutable collection of all members of this annotation, never {@code null} */ Collection 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 41693820..d7222d51 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMember.java @@ -1,18 +1,24 @@ package jakarta.enterprise.lang.model; /** - * Represents an annotation member and associated {@link jakarta.enterprise.lang.model.AnnotationMemberValue}. + * An annotation member: name and {@link AnnotationMemberValue value}. + * + * @see #name() + * @see #value() */ +// TODO maybe remove this and let AnnotationInfo.members() return Map? public interface AnnotationMember { /** - * @return The name of the annotation member. Never {@code null}. + * Returns the name of this annotation member. + * + * @return the name of this annotation member, never {@code null} */ String name(); /** - * Supplies the {@link jakarta.enterprise.lang.model.AnnotationMemberValue} associated with the annotation member. + * Returns the {@link AnnotationMemberValue value} of this annotation member. * - * @return The value of the annotation member. Never {@code null}. + * @return the value of this annotation member, never {@code null} */ AnnotationMemberValue value(); } diff --git a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java index 4cabe36c..8afc19f3 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationMemberValue.java @@ -2,261 +2,319 @@ import jakarta.enterprise.lang.model.declarations.ClassInfo; import jakarta.enterprise.lang.model.types.Type; + import java.util.List; /** - * Models the value of an {@link jakarta.enterprise.lang.model.AnnotationMember}. + * 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 member. + * The kind of the annotation member value. */ enum Kind { /** - * A primitive {@link java.lang.Boolean}. + * A primitive {@code boolean}. */ BOOLEAN, /** - * A primitive {@link java.lang.Byte}. + * A primitive {@code byte}. */ BYTE, /** - * A primitive {@link java.lang.Short}. + * A primitive {@code short}. */ SHORT, /** - * A primitive {@link java.lang.Integer}. + * A primitive {@code int}. */ INT, /** - * A primitive {@link java.lang.Long}. + * A primitive {@code long}. */ LONG, /** - * A primitive {@link java.lang.Float}. + * A primitive {@code float}. */ FLOAT, /** - * A primitive {@link java.lang.Double}. + * A primitive {@code double}. */ DOUBLE, /** - * A primitive {@link java.lang.Character}. + * A primitive {@code char}. */ CHAR, /** - * A {@link java.lang.String} value. + * A {@link String} value. */ STRING, /** - * An {@link java.lang.Enum} value. + * An {@link Enum} value. */ ENUM, /** - * A {@link java.lang.Class} value modelled as {@link jakarta.enterprise.lang.model.types.Type}. + * A {@link Class} value. Represented as {@link jakarta.enterprise.lang.model.types.Type}. */ CLASS, /** - * An array value. + * A nested {@link java.lang.annotation.Annotation Annotation} value. + * Represented as {@link AnnotationInfo}. */ - ARRAY, + NESTED_ANNOTATION, /** - * A nested annotation definition. + * An array value. */ - NESTED_ANNOTATION, + ARRAY, } /** - * @return The kind of the annotation member. Never {@code null}. + * Returns the kind of the annotation member value. + * + * @return the kind of the annotation member value, never {@code null} */ Kind kind(); /** - * @return Returns {@code true} if the kind is a {@code boolean}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code boolean}, {@code false} otherwise */ default boolean isBoolean() { return kind() == Kind.BOOLEAN; } /** - * @return Returns {@code true} if the kind is a {@code byte}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code byte}, {@code false} otherwise */ default boolean isByte() { return kind() == Kind.BYTE; } /** - * @return Returns {@code true} if the kind is a {@code short}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code short}, {@code false} otherwise */ default boolean isShort() { return kind() == Kind.SHORT; } /** - * @return Returns {@code true} if the kind is a {@code int}, {@code false} otherwise. + * @return {@code true} if the kind is an {@code int}, {@code false} otherwise */ default boolean isInt() { return kind() == Kind.INT; } /** - * @return Returns {@code true} if the kind is a {@code long}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code long}, {@code false} otherwise */ default boolean isLong() { return kind() == Kind.LONG; } /** - * @return Returns {@code true} if the kind is a {@code float}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code float}, {@code false} otherwise */ default boolean isFloat() { return kind() == Kind.FLOAT; } /** - * @return Returns {@code true} if the kind is a {@code double}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code double}, {@code false} otherwise */ default boolean isDouble() { return kind() == Kind.DOUBLE; } /** - * @return Returns {@code true} if the kind is a {@code char}, {@code false} otherwise. + * @return {@code true} if the kind is a {@code char}, {@code false} otherwise */ default boolean isChar() { return kind() == Kind.CHAR; } /** - * @return Returns {@code true} if the kind is a {@link String}, {@code false} otherwise. + * @return {@code true} if the kind is a {@link String}, {@code false} otherwise */ default boolean isString() { return kind() == Kind.STRING; } /** - * @return Returns {@code true} if the kind is a {@link Enum}, {@code false} otherwise. + * @return {@code true} if the kind is an {@link Enum}, {@code false} otherwise */ default boolean isEnum() { return kind() == Kind.ENUM; } /** - * @return Returns {@code true} if the kind is a {@link Class}, {@code false} otherwise. + * @return {@code true} if the kind is a {@link Class}, {@code false} otherwise */ default boolean isClass() { return kind() == Kind.CLASS; } /** - * @return Returns {@code true} if the kind is an array, {@code false} otherwise. + * @return {@code true} if the kind is a nested {@link java.lang.annotation.Annotation Annotation}, {@code false} otherwise */ - default boolean isArray() { - return kind() == Kind.ARRAY; + default boolean isNestedAnnotation() { + return kind() == Kind.NESTED_ANNOTATION; } /** - * @return Returns {@code true} if the kind is an {@link java.lang.annotation.Annotation}, {@code false} otherwise. + * @return {@code true} if the kind is an array, {@code false} otherwise */ - default boolean isNestedAnnotation() { - return kind() == Kind.NESTED_ANNOTATION; + default boolean isArray() { + return kind() == Kind.ARRAY; } /** - * Return the value as a boolean. - * @return The boolean value + * Returns the value as a boolean. + * + * @return the boolean value + * @throws IllegalStateException if this annotation member value is not a boolean */ boolean asBoolean(); /** - * Return the value as a byte. - * @return The byte value - * @throws NumberFormatException if the value cannot be represented as a byte. + * Returns the value as a byte. + * + * @return the byte value + * @throws IllegalStateException if the value cannot be represented as a byte */ byte asByte(); /** - * Return the value as a short. - * @return The short value - * @throws NumberFormatException if the value cannot be represented as a short. + * Returns the value as a short. + * + * @return the short value + * @throws IllegalStateException if the value cannot be represented as a short. */ short asShort(); /** - * Return the value as an int. - * @return The int value - * @throws java.lang.IllegalStateException if the value cannot be represented as an int. + * Returns the value as an int. + * + * @return the int value + * @throws IllegalStateException if the value cannot be represented as an int. */ int asInt(); /** - * Return the value as a long. - * @return The long value - * @throws java.lang.IllegalStateException if the value cannot be represented as a long. + * Returns the value as a long. + * + * @return the long value + * @throws IllegalStateException if the value cannot be represented as a long. */ long asLong(); /** - * Return the value as a float. - * @return The float value - * @throws java.lang.IllegalStateException if the value cannot be represented as a float. + * Returns the value as a float. + * + * @return the float value + * @throws IllegalStateException if the value cannot be represented as a float. */ float asFloat(); /** - * Return the value as a double. - * @return The double value - * @throws java.lang.IllegalStateException if the value cannot be represented as a double. + * Returns the value as a double. + * + * @return the double value + * @throws IllegalStateException if the value cannot be represented as a double. */ double asDouble(); /** - * Return the value as a char. - * @return The char value - * @throws java.lang.IllegalStateException if the value cannot be represented as a double. + * Returns the value as a char. + * + * @return the char value + * @throws IllegalStateException if this annotation member value is not a char */ char asChar(); /** - * Return the value as a string. - * @return A string representing the value. Never {@code null}. + * Returns the value as a String. + * + * @return the String value + * @throws IllegalStateException if this annotation member value is not a String */ String asString(); /** - * Return the value to an enum instance. - * @param enumType The enum type - * @param The enum generic type - * @return The enum instance - * @throws java.lang.IllegalStateException if the enum value cannot be established from the given argument + * 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); /** - * Return the enum type that an enum value represents. + * Returns the enum type of the annotation member value. * - * @return A {@link jakarta.enterprise.lang.model.declarations.ClassInfo} representing the type of an enum value. + * @return a {@link ClassInfo} representing the enum type + * @throws IllegalStateException if this annotation member value is not an enum value */ ClassInfo asEnumClass(); /** - * Return the type of the value. Valid types include {@link jakarta.enterprise.lang.model.types.PrimitiveType}, {@link jakarta.enterprise.lang.model.types.VoidType} and {@link jakarta.enterprise.lang.model.types.ClassType}. + * Returns the enum constant of the annotation member value. * - * @return The {@link jakarta.enterprise.lang.model.types.Type} of the value. + * @return the enum constant + * @throws IllegalStateException if this annotation member value is not an enum value */ - Type asType(); // can be a VoidType, PrimitiveType or ClassType + String asEnumConstant(); /** - * Allows retrieving the values of an array when {@link #isArray()} returns {@code true}. + * 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 An immutable list of {@link jakarta.enterprise.lang.model.AnnotationMemberValue} representing the array values. + * @return the class value, as a {@link Type} + * @throws IllegalStateException if this annotation member value is not a class value */ - List asArray(); + Type asType(); /** - * Allows retrieving the a nested annotation value as an an instance of {@link jakarta.enterprise.lang.model.AnnotationInfo} when {@link #isNestedAnnotation()} returns {@code true}. - * @return The {@link jakarta.enterprise.lang.model.AnnotationInfo} instance. - * @throws java.lang.IllegalStateException If the value is not an annotation. + * 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(); } diff --git a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationTarget.java b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationTarget.java index 1904527b..f7cabc04 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/AnnotationTarget.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/AnnotationTarget.java @@ -2,12 +2,13 @@ import jakarta.enterprise.lang.model.declarations.DeclarationInfo; import jakarta.enterprise.lang.model.types.Type; + import java.lang.annotation.Annotation; import java.util.Collection; import java.util.function.Predicate; /** - * An Annotation target is anything that can be annotated. + * An annotation target is anything that can be annotated. * That is: * *
    @@ -16,88 +17,100 @@ *
  • a type use, such as a type of method parameter, a type of field, a type argument, etc. See {@link jakarta.enterprise.lang.model.types.Type}.
  • *
* + * Annotations are represented as {@link AnnotationInfo}, so that implementations of this API are not required + * to instantiate the annotation type. * * @since 4.0.0 */ public interface AnnotationTarget { // TODO specify equals/hashCode (for the entire .lang.model hierarchy) - // TODO settle on using Optional everywhere, or allowing null everywhere; it's a mix right now - // TODO what about declared vs not declared annotations? + // TODO we decided that we won't use Optional and will just return null; need to make this consistent everywhere + // TODO what about declared vs not declared (inherited) annotations? + // probably should always return all, including inherited, that's what Portable Extensions do /** - * Returns whether this annotation target a {@link jakarta.enterprise.lang.model.declarations.DeclarationInfo}. + * Returns whether this annotation target is a {@link DeclarationInfo declaration}. * + * @return {@code true} if this is a declaration, {@code false} otherwise * @see jakarta.enterprise.lang.model.declarations.DeclarationInfo - * @return Will return {@code true} if it is a {@link jakarta.enterprise.lang.model.declarations.DeclarationInfo} and {@code false} otherwise */ boolean isDeclaration(); /** - * Returns whether this annotation target is a {@link jakarta.enterprise.lang.model.types.Type}. - * @return Will return {@code true} if it is a {@link jakarta.enterprise.lang.model.types.Type} and {@code false} otherwise + * Returns whether this annotation target is a {@link Type type}. + * + * @return {@code true} if this is a type, {@code false} otherwise + * @see jakarta.enterprise.lang.model.types.Type */ boolean isType(); /** - * Coerce this annotation target to a {@link jakarta.enterprise.lang.model.declarations.DeclarationInfo}. - * @return The {@link jakarta.enterprise.lang.model.declarations.DeclarationInfo} instance, never {@code null} - * @throws java.lang.IllegalStateException If {@link #isDeclaration()} returns {@code false} + * Returns this annotation target as a {@link DeclarationInfo declaration}. + * + * @return this declaration, never {@code null} + * @throws IllegalStateException if {@link #isDeclaration()} returns {@code false} */ DeclarationInfo asDeclaration(); /** - * Coerce this annotation target to a {@link jakarta.enterprise.lang.model.types.Type}. - * @return The {@link jakarta.enterprise.lang.model.types.Type} instance, never {@code null} - * @throws java.lang.IllegalStateException If {@link #isType()} returns {@code false} + * Returns this annotation target as a {@link Type type}. + * + * @return this type, never {@code null} + * @throws IllegalStateException if {@link #isType()} returns {@code false} */ Type asType(); /** - * Return with the given annotation type is present on this annotation target. + * Returns whether an annotation of given type is present on this annotation target. * - * @param annotationType The annotation type, never {@code null} - * @return Returns {@code true} if the given annotation type is present on this annotation info, {@code false} otherwise. - * @throws java.lang.IllegalArgumentException If {@code null} is passed as an argument + * @param annotationType the annotation type, must not be {@code null} + * @return {@code true} if given annotation type is present on this annotation target, {@code false} otherwise */ boolean hasAnnotation(Class annotationType); /** - * Evaluate the given predicate, returning {@code true} if the predicate matches any {@link jakarta.enterprise.lang.model.AnnotationInfo} present on this annotation target. - * @param predicate The predicate, never {@code null} - * @return Returns {@code true} if the given predicate matches any {@link jakarta.enterprise.lang.model.AnnotationInfo} instance, {@code false} otherwise. - * @throws java.lang.IllegalArgumentException If {@code null} is passed as an argument + * Returns whether given predicate matches any annotation present on this annotation target. + * + * @param predicate annotation predicate, must not be {@code null} + * @return {@code true} if given predicate matches any annotation present on this annotation target, {@code false} otherwise. */ boolean hasAnnotation(Predicate> predicate); /** - * Obtains an {@link jakarta.enterprise.lang.model.AnnotationInfo} for the given annotation type if it is present on this annotation target. - * @param annotationType The annotation type, never {@code null} - * @param The annotation generic type - * @return The {@link jakarta.enterprise.lang.model.AnnotationInfo} or {@code null} if it doesn't exist. - * @throws java.lang.IllegalArgumentException If {@code null} is passed as an argument + * Returns an annotation of given type, if it is present on this annotation target. + * + * @param annotationType the annotation type, must not be {@code null} + * @param the annotation generic type + * @return the {@link AnnotationInfo} or {@code null} if no such annotation is present on this annotation target */ AnnotationInfo annotation(Class annotationType); /** - * Obtains a collection of the repeatable {@link jakarta.enterprise.lang.model.AnnotationInfo} instances for the given repeatable annotation type (An annotation type that is annotated with {@link java.lang.annotation.Repeatable}). + * Returns a collection of annotations of given repeatable annotation type + * (an annotation type that is meta-annotated {@link java.lang.annotation.Repeatable @Repeatable}) + * present on this annotation target. Returns an empty collection if no such + * annotation is present. * - * @param annotationType The annotation type - * @return An immutable collection of {@link jakarta.enterprise.lang.model.AnnotationInfo}, never {@code null} + * @param annotationType the {@code @Repeatable} annotation type, must not be {@code null} + * @param the annotation generic type + * @return immutable collection of {@link AnnotationInfo}, never {@code null} */ Collection> repeatableAnnotation(Class annotationType); /** - * Obtains a collection of the {@link jakarta.enterprise.lang.model.AnnotationInfo} instances that match the given predicate. + * Returns a collection of all annotations present on this annotation target that match given predicate. + * Returns an empty collection if no such annotation is present. * - * @param predicate The predicate used to evaluate matching {@link jakarta.enterprise.lang.model.AnnotationInfo} instances. - * @return An immutable collection of {@link jakarta.enterprise.lang.model.AnnotationInfo}, never {@code null} - * @throws java.lang.IllegalArgumentException If {@code null} is passed as an argument + * @param predicate annotation predicate, must not be {@code null} + * @return immutable collection of {@link AnnotationInfo}, never {@code null} */ Collection> annotations(Predicate> predicate); /** - * Obtains all of the {@link jakarta.enterprise.lang.model.AnnotationInfo} instances for the given annotation target. - * @return An immutable collection of {@link jakarta.enterprise.lang.model.AnnotationInfo}, never {@code null} + * Returns a collection of all annotations present on this annotation target. + * Returns an empty collection if no annotation is present. + * + * @return immutable collection of {@link AnnotationInfo}, never {@code null} */ Collection> annotations(); } diff --git a/api/src/main/java/jakarta/enterprise/lang/model/declarations/ClassInfo.java b/api/src/main/java/jakarta/enterprise/lang/model/declarations/ClassInfo.java index 0c8acd69..61a36753 100644 --- a/api/src/main/java/jakarta/enterprise/lang/model/declarations/ClassInfo.java +++ b/api/src/main/java/jakarta/enterprise/lang/model/declarations/ClassInfo.java @@ -2,6 +2,7 @@ import jakarta.enterprise.lang.model.types.Type; import jakarta.enterprise.lang.model.types.TypeVariable; + import java.util.Collection; import java.util.List; @@ -12,8 +13,20 @@ public interface ClassInfo extends DeclarationInfo { // TODO remove the type parameter? // TODO nested classes don't provide access to enclosing class, but that might be OK for our purposes? + /** + * Returns the binary name of this class, as defined by The Java™ Language Specification; + * in other words, the class name as returned by {@link Class#getName()}. + * + * @return binary name of this class, never {@code null} + */ String name(); + /** + * Returns the simple name of this class, as defined by The Java™ Language Specification; + * in other words, the class name as returned by {@link Class#getSimpleName()}. + * + * @return simple name of this class, never {@code null} + */ String simpleName(); PackageInfo packageInfo();