Skip to content

Commit

Permalink
initial Build Compatible Extension API proposal
Browse files Browse the repository at this point in the history
Signed-off-by: Ladislav Thon <lthon@redhat.com>
  • Loading branch information
Ladicek committed Jun 1, 2021
1 parent 0988d2c commit 7db630d
Show file tree
Hide file tree
Showing 54 changed files with 2,341 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit 7db630d

Please sign in to comment.