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 Sep 16, 2020
1 parent 5c59e42 commit 2b18a94
Show file tree
Hide file tree
Showing 47 changed files with 2,035 additions and 0 deletions.
186 changes: 186 additions & 0 deletions api/src/main/java/cdi/lite/extension/AppArchive.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package cdi.lite.extension;

import cdi.lite.extension.model.declarations.ClassInfo;
import cdi.lite.extension.model.declarations.FieldInfo;
import cdi.lite.extension.model.declarations.MethodInfo;
import cdi.lite.extension.model.types.Type;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.stream.Stream;

public interface AppArchive {
ClassQuery classes();

MethodQuery constructors(); // no static initializers

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

FieldQuery fields();

/**
* The {@code exactly}, {@code subtypeOf} and {@code supertypeOf} 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)
* .find()
* }</pre>
* returns 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)
* .find()
* }</pre>
* returns all classes annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface ClassQuery {
ClassQuery exactly(Class<?> clazz);

ClassQuery exactly(ClassInfo<?> clazz);

ClassQuery subtypeOf(Class<?> clazz);

ClassQuery subtypeOf(ClassInfo<?> clazz);

ClassQuery supertypeOf(Class<?> clazz);

ClassQuery supertypeOf(ClassInfo<?> clazz);

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

ClassQuery annotatedWith(ClassInfo<?> annotationType);

Collection<ClassInfo<?>> find();

Stream<ClassInfo<?>> stream();
}

/**
* 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))
* .find()
* }</pre>
* returns 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))
* .find()
* }</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)
* .find()
* }</pre>
* returns 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)
* .find()
* }</pre>
* returns all methods annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface MethodQuery {
MethodQuery declaredOn(ClassQuery classes);

/**
* Equivalent to {@code withReturnType(types.of(type))}, where {@code types} is {@link Types}.
*/
MethodQuery withReturnType(Class<?> type);

MethodQuery withReturnType(Type type);

// TODO parameters?

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

MethodQuery annotatedWith(ClassInfo<?> annotationType);

Collection<MethodInfo<?>> find();

Stream<MethodInfo<?>> stream();
}

/**
* 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))
* .find()
* }</pre>
* returns 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))
* .find()
* }</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)
* .find()
* }</pre>
* returns 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)
* .find()
* }</pre>
* returns all fields annotated either with {@code @Foo} or with {@code @Bar} (or both).
*/
interface FieldQuery {
FieldQuery declaredOn(ClassQuery classes);

/**
* Equivalent to {@code ofType(types.of(type))}, where {@code types} is {@link Types}.
*/
FieldQuery ofType(Class<?> type);

FieldQuery ofType(Type type);

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

FieldQuery annotatedWith(ClassInfo<?> annotationType);

Collection<FieldInfo<?>> find();

Stream<FieldInfo<?>> stream();
}
}
140 changes: 140 additions & 0 deletions api/src/main/java/cdi/lite/extension/AppDeployment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package cdi.lite.extension;

import cdi.lite.extension.beans.BeanInfo;
import cdi.lite.extension.beans.ObserverInfo;
import cdi.lite.extension.model.declarations.ClassInfo;
import cdi.lite.extension.model.types.Type;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.stream.Stream;

public interface AppDeployment {
BeanQuery beans();

ObserverQuery observers();

/**
* The {@code scope} methods are additive.
* When called multiple times, they form a union of requested scope types (not an intersection).
* For example,
* <pre>{@code
* appDeployment.beans()
* .scope(Foo.class)
* .scope(Bar.class)
* .find()
* }</pre>
* returns all beans with the {@code @Foo} scope or the {@code @Bar} scope.
* <p>
* The {@code type} methods are additive.
* When called multiple times, they form a union of requested bean types (not an intersection).
* For example,
* <pre>{@code
* appDeployment.beans()
* .type(Foo.class)
* .type(Bar.class)
* .find()
* }</pre>
* returns all beans with the {@code Foo} type or the {@code Bar} type (or both).
* Note that bean type is not just the class which declares the bean (or return type of a producer method,
* or type of producer field). All superclasses and superinterfaces are also included in the set of bean types.
* <p>
* The {@code qualifier} methods are additive.
* When called multiple times, they form a union of requested qualifiers (not an intersection).
* For example,
* <pre>{@code
* appDeployment.beans()
* .qualifier(Foo.class)
* .qualifier(Bar.class)
* .find()
* }</pre>
* returns all beans with the {@code @Foo} qualifier or the {@code @Bar} qualifier (or both).
* <p>
* The {@code declaringClass} methods are additive.
* When called multiple times, they form a union of requested declaration classes (not an intersection).
* For example,
* <pre>{@code
* appDeployment.beans()
* .declaringClass(Foo.class)
* .declaringClass(Bar.class)
* .find()
* }</pre>
* returns all beans declared on the {@code Foo} class or the {@code Bar} class.
*/
interface BeanQuery {
BeanQuery scope(Class<? extends Annotation> scopeAnnotation);

BeanQuery scope(ClassInfo<?> scopeAnnotation);

BeanQuery type(Class<?> beanType);

BeanQuery type(ClassInfo<?> beanType);

BeanQuery type(Type beanType);

BeanQuery qualifier(Class<? extends Annotation> qualifierAnnotation);

BeanQuery qualifier(ClassInfo<?> qualifierAnnotation);

BeanQuery declaringClass(Class<?> declarationClass);

BeanQuery declaringClass(ClassInfo<?> declarationClass);

Collection<BeanInfo<?>> find();

Stream<BeanInfo<?>> stream();
}

/**
* The {@code observedType} methods are additive.
* When called multiple times, they form a union of requested observer types (not an intersection).
* For example,
* <pre>{@code
* appDeployment.observers()
* .observedType(Foo.class)
* .observedType(Bar.class)
* .find()
* }</pre>
* returns all observers that observe the {@code Foo} event type or the {@code Bar} event type.
* <p>
* The {@code qualifier} methods are additive.
* When called multiple times, they form a union of requested qualifiers (not an intersection).
* For example,
* <pre>{@code
* appDeployment.observers()
* .qualifier(Foo.class)
* .qualifier(Bar.class)
* .find()
* }</pre>
* returns all observers with the {@code @Foo} qualifier or the {@code @Bar} qualifier (or both).
* <p>
* The {@code declaringClass} methods are additive.
* When called multiple times, they form a union of requested declaration classes (not an intersection).
* For example,
* <pre>{@code
* appDeployment.observers()
* .declaringClass(Foo.class)
* .declaringClass(Bar.class)
* .find()
* }</pre>
* returns all observers declared on the {@code Foo} class or the {@code Bar} class.
*/
interface ObserverQuery {
ObserverQuery observedType(Class<?> beanType);

ObserverQuery observedType(ClassInfo<?> beanType);

ObserverQuery observedType(Type beanType);

ObserverQuery qualifier(Class<? extends Annotation> qualifierAnnotation);

ObserverQuery qualifier(ClassInfo<?> qualifierAnnotation);

ObserverQuery declaringClass(Class<?> declarationClass);

ObserverQuery declaringClass(ClassInfo<?> declarationClass);

Collection<ObserverInfo<?>> find();

Stream<ObserverInfo<?>> stream();
}
}
24 changes: 24 additions & 0 deletions api/src/main/java/cdi/lite/extension/ExtensionPriority.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cdi.lite.extension;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Allows specifying priority of extensions.
* <p>
* Extensions with specified priority always precede extensions without any priority.
* Extension with highest priority get invoked first. If two extensions have equal
* priority, the ordering is undefined.
* TODO should really figure out if low number = high priority or otherwise, preferrably
* so that it's consistent with common usages of `@Priority`
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtensionPriority {
/**
* The priority value.
*/
int value();
}

0 comments on commit 2b18a94

Please sign in to comment.