Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial Build Compatible Extension API proposal #451

Merged
merged 1 commit into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,23 @@
package jakarta.enterprise.inject.build.compatible.spi;

import jakarta.enterprise.lang.model.AnnotationAttribute;
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<? extends Annotation> annotationType, AnnotationAttribute... attributes);

void addAnnotation(ClassInfo<?> annotationType, AnnotationAttribute... attributes);

void addAnnotation(AnnotationInfo annotation);

void addAnnotation(Annotation annotation);

void removeAnnotation(Predicate<AnnotationInfo> predicate);

void removeAllAnnotations();
}
@@ -0,0 +1,84 @@
package jakarta.enterprise.inject.build.compatible.spi;

import jakarta.enterprise.lang.model.AnnotationAttribute;
import jakarta.enterprise.lang.model.AnnotationAttributeValue;
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 {
AnnotationAttributeValue value(boolean value);

AnnotationAttributeValue value(byte value);

AnnotationAttributeValue value(short value);

AnnotationAttributeValue value(int value);

AnnotationAttributeValue value(long value);

AnnotationAttributeValue value(float value);

AnnotationAttributeValue value(double value);

AnnotationAttributeValue value(char value);

AnnotationAttributeValue value(String value);

AnnotationAttributeValue value(Enum<?> enumValue);

AnnotationAttributeValue value(Class<? extends Enum<?>> enumType, String enumValue);

AnnotationAttributeValue value(ClassInfo<?> enumType, String enumValue);

AnnotationAttributeValue value(Class<?> value);

AnnotationAttributeValue annotationValue(Class<? extends Annotation> annotationType, AnnotationAttribute... attributes);

AnnotationAttributeValue annotationValue(ClassInfo<?> annotationType, AnnotationAttribute... attributes);

AnnotationAttributeValue annotationValue(AnnotationInfo annotation);

AnnotationAttributeValue annotationValue(Annotation annotation);

AnnotationAttribute attribute(String name, boolean value);

AnnotationAttribute attribute(String name, byte value);

AnnotationAttribute attribute(String name, short value);

AnnotationAttribute attribute(String name, int value);

AnnotationAttribute attribute(String name, long value);

AnnotationAttribute attribute(String name, float value);

AnnotationAttribute attribute(String name, double value);

AnnotationAttribute attribute(String name, char value);

AnnotationAttribute attribute(String name, String value);

AnnotationAttribute attribute(String name, Enum<?> enumValue);

AnnotationAttribute attribute(String name, Class<? extends Enum<?>> enumType, String enumValue);

AnnotationAttribute attribute(String name, ClassInfo<?> enumType, String enumValue);

AnnotationAttribute attribute(String name, Class<?> value);

AnnotationAttribute arrayAttribute(String name, AnnotationAttributeValue... values);

AnnotationAttribute arrayAttribute(String name, List<AnnotationAttributeValue> values);

AnnotationAttribute annotationAttribute(String name, Class<? extends Annotation> annotationType,
AnnotationAttribute... attributes);

AnnotationAttribute annotationAttribute(String name, ClassInfo<?> annotationType, AnnotationAttribute... attributes);

AnnotationAttribute annotationAttribute(String name, AnnotationInfo annotation);

AnnotationAttribute annotationAttribute(String name, Annotation annotation);
}
@@ -0,0 +1,162 @@
package jakarta.enterprise.inject.build.compatible.spi;

import jakarta.enterprise.lang.model.declarations.ClassInfo;
import jakarta.enterprise.lang.model.declarations.FieldInfo;
import jakarta.enterprise.lang.model.declarations.MethodInfo;
import jakarta.enterprise.lang.model.types.Type;
import java.lang.annotation.Annotation;
import java.util.function.Consumer;

// TODO remove entirely?
public interface AppArchive {
ClassQuery classes();

MethodQuery constructors(); // no static initializers

MethodQuery methods(); // no constructors nor static initializers

FieldQuery fields();

/**
* The {@code exactly} and {@code subtypeOf} methods are additive.
* When called multiple times, they form a union of requested classes (not an intersection).
* For example,
* <pre>{@code
* appArchive.classes()
* .exactly(Foo.class)
* .subtypeOf(Bar.class)
* .forEach(...)
* }</pre>
* runs given code for the {@code Foo} class and all subtypes of the {@code Bar} class.
* <p>
* The {@code annotatedWith} methods are additive.
* When called multiple times, they form a union of requested annotations (not an intersection).
* For example,
* <pre>{@code
* appArchive.classes()
* .annotatedWith(Foo.class)
* .annotatedWith(Bar.class)
* .forEach(...)
* }</pre>
* runs given code for all classes annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface ClassQuery {
ClassQuery exactly(Class<?> clazz);

ClassQuery subtypeOf(Class<?> clazz);

ClassQuery annotatedWith(Class<? extends Annotation> annotationType);

void forEach(Consumer<ClassInfo<?>> consumer);
}

/**
* The {@code declaredOn} method is additive.
* When called multiple times, it forms a union of requested classes (not an intersection).
* For example,
* <pre>{@code
* appArchive.methods()
* .declaredOn(appArchive.classes().exactly(Foo.class))
* .declaredOn(appArchive.classes().subtypeOf(Bar.class))
* .forEach(...)
* }</pre>
* runs given code for all methods declared on the {@code Foo} class and on all subtypes of the {@code Bar} class.
* Note that this example can be rewritten as
* <pre>{@code
* appArchive.methods()
* .declaredOn(appArchive.classes().exactly(Foo.class).subtypeOf(Bar.class))
* .forEach(...)
* }</pre>
* which is probably easier to understand.
* <p>
* The {@code withReturnType} methods are additive.
* When called multiple times, they form a union of requested return types (not an intersection).
* For example,
* <pre>{@code
* appArchive.methods()
* .withReturnType(Foo.class)
* .withReturnType(Bar.class)
* .forEach(...)
* }</pre>
* runs given code for all methods that return either {@code Foo} or {@code Bar}.
* <p>
* The {@code annotatedWith} methods are additive.
* When called multiple times, they form a union of requested annotations (not an intersection).
* For example,
* <pre>{@code
* appArchive.methods()
* .annotatedWith(Foo.class)
* .annotatedWith(Bar.class)
* .forEach(...)
* }</pre>
* runs given code for all methods annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface MethodQuery {
MethodQuery declaredOn(ClassQuery classes);

// equivalent to `withReturnType(Types.of(type))`
MethodQuery withReturnType(Class<?> type);

MethodQuery withReturnType(Type type);

// TODO parameters?

MethodQuery annotatedWith(Class<? extends Annotation> annotationType);

void forEach(Consumer<MethodInfo<?>> consumer);
}

/**
* The {@code declaredOn} method is additive.
* When called multiple times, it forms a union of requested classes (not an intersection).
* For example,
* <pre>{@code
* appArchive.fields()
* .declaredOn(appArchive.classes().exactly(Foo.class))
* .declaredOn(appArchive.classes().subtypeOf(Bar.class))
* .forEach(...)
* }</pre>
* runs given code for all fields declared on the {@code Foo} class and on all subtypes of the {@code Bar} class.
* Note that this example can be rewritten as
* <pre>{@code
* appArchive.fields()
* .declaredOn(appArchive.classes().exactly(Foo.class).subtypeOf(Bar.class))
* .forEach()
* }</pre>
* which is probably easier to understand.
* <p>
* The {@code ofType} methods are additive.
* When called multiple times, they form a union of requested field types (not an intersection).
* For example,
* <pre>{@code
* appArchive.fields()
* .ofType(Foo.class)
* .ofType(Bar.class)
* .forEach()
* }</pre>
* runs given code for all fields that are of type either {@code Foo} or {@code Bar}.
* <p>
* The {@code annotatedWith} methods are additive.
* When called multiple times, they form a union of requested annotations (not an intersection).
* For example,
* <pre>{@code
* appArchive.fields()
* .annotatedWith(Foo.class)
* .annotatedWith(Bar.class)
* .forEach(...)
* }</pre>
* runs given code for all fields annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface FieldQuery {
FieldQuery declaredOn(ClassQuery classes);

// equivalent to `withReturnType(Types.of(type))`
FieldQuery ofType(Class<?> type);

FieldQuery ofType(Type type);

FieldQuery annotatedWith(Class<? extends Annotation> annotationType);

void forEach(Consumer<FieldInfo<?>> consumer);
}
}
@@ -0,0 +1,10 @@
package jakarta.enterprise.inject.build.compatible.spi;

// TODO better name
public interface AppArchiveBuilder {
void add(String fullyQualifiedClassName);

// TODO adds the type itself or not? (in theory yes, as subtyping is reflexive)
// TODO looks like it can't be implemented on top of Portable Extensions, so maybe remove?
void addSubtypesOf(String fullyQualifiedClassName);
}
@@ -0,0 +1,66 @@
package jakarta.enterprise.inject.build.compatible.spi;

import jakarta.enterprise.lang.model.types.Type;
import java.lang.annotation.Annotation;
import java.util.function.Consumer;

// TODO remove entirely, if we remove AppArchive/AppDeployment
// TODO maybe AppArchiveConfig shouldn't extend AppArchive, and *ConfigQuery shouldn't extend *Query
public interface AppArchiveConfig extends AppArchive {
@Override
ClassConfigQuery classes();

@Override
MethodConfigQuery constructors(); // no static initializers

@Override
MethodConfigQuery methods(); // no constructors nor static initializers

@Override
FieldConfigQuery fields();

interface ClassConfigQuery extends ClassQuery {
@Override
ClassConfigQuery exactly(Class<?> clazz);

@Override
ClassConfigQuery subtypeOf(Class<?> clazz);

@Override
ClassConfigQuery annotatedWith(Class<? extends Annotation> annotationType);

void configure(Consumer<ClassConfig<?>> consumer);
}

interface MethodConfigQuery extends MethodQuery {
@Override
MethodConfigQuery declaredOn(ClassQuery classes);

@Override
MethodConfigQuery withReturnType(Class<?> type);

@Override
MethodConfigQuery withReturnType(Type type);

@Override
MethodConfigQuery annotatedWith(Class<? extends Annotation> annotationType);

void configure(Consumer<MethodConfig<?>> consumer);
}

interface FieldConfigQuery extends FieldQuery {
@Override
FieldConfigQuery declaredOn(ClassQuery classes);

@Override
FieldConfigQuery ofType(Class<?> type);

@Override
FieldConfigQuery ofType(Type type);

@Override
FieldConfigQuery annotatedWith(Class<? extends Annotation> annotationType);

void configure(Consumer<FieldConfig<?>> consumer);
}
}