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

cdi-468 Split Spec doc to introduce CDI Lite #470

Merged
merged 11 commits into from
May 20, 2021
21 changes: 14 additions & 7 deletions spec/src/main/asciidoc/architecture.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ This specification defines a powerful set of complementary services that help to
* A sophisticated, typesafe _dependency injection_ mechanism, including the ability to select dependencies at either development or deployment time, without verbose configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to define cdi full and cdi liter concept first in this chapter and then refer to it.

* Support for Jakarta EE modularity and the Jakarta EE component architecture - the modular structure of a Jakarta EE application is taken into account when resolving dependencies between Jakarta EE components
* Integration with the Jakarta Unified Expression Language (EL), allowing any contextual object to be used directly within a Jakarta Server Faces or JSP page
* The ability to _decorate_ injected objects
* The ability to _decorate_ injected objects (only in {cdi_full} environment)
* The ability to associate interceptors to objects via typesafe _interceptor bindings_
* An _event notification_ model
* A web _conversation context_ in addition to the three standard web contexts defined by the Jakarta Servlets specification
* A web _conversation context_ in addition to the three standard web contexts defined by the Jakarta Servlets specification (only in {cdi_full} environment)
* An SPI allowing _portable extensions_ to integrate cleanly with the container


Expand All @@ -27,7 +27,7 @@ In particular, Jakarta Enterprise Bean components may be used as Jakarta Server
It's even possible to integrate with third-party frameworks.
A portable extension may provide objects to be injected or obtain contextual instances using the dependency injection service. The framework may even raise and observe events using the event notification service.

An application that takes advantage of these services may be designed to execute in either the Jakarta EE environment or the Java SE environment.
An application that takes advantage of these services may be designed to execute in the Jakarta EE environment, the Java SE environment, or in other environments that implement {cdi_lite}.
If the application uses Jakarta EE services such as transaction management and persistence in the Java SE environment, the services are usually restricted to, at most, the subset defined for embedded usage by the Jakarta Enterprise Bean specification.

=== Contracts
Expand All @@ -41,13 +41,15 @@ This specification defines the responsibilities of:
This runtime environment is called the _container_.
For example, the container might be a Jakarta EE container or an embeddable Jakarta Enterprise Bean container.

<<concepts>>, <<implementation>>, <<inheritance>>, <<interceptors>>, <<decorator_bean>> and <<observer_methods>> define the programming model for Jakarta EE components that take advantage of the services defined by this specification, the responsibilities of the component developer, and the annotations used by the component developer to specify metadata.
<<concepts>>, <<implementation>>, <<inheritance>>, <<interceptors>> and <<observer_methods>> define the programming model for application components that take advantage of the services defined by this specification, the responsibilities of the component developer, and the annotations used by the component developer to specify metadata.
{cdi_full} adds <<specialization>> and <<decorator_bean>>.

<<injection_and_resolution>>, <<contexts>>, <<lifecycle>>, <<decorators>>, <<events>> and <<interceptor_resolution>> define the semantics and behavior of the services, the responsibilities of the container implementation and the APIs used by the application to interact directly with the container.
<<injection_and_resolution>>, <<contexts>>, <<lifecycle>>, <<events>> and <<interceptor_resolution>> define the semantics and behavior of the services, the responsibilities of the container implementation and the APIs used by the application to interact directly with the container.
{cdi_full} adds <<decorators>>.

<<packaging_deployment>> defines how Jakarta EE applications that use the services defined by this specification must be packaged into bean archives, and the responsibilities of the container implementation at application initialization time.
<<packaging_deployment_lite>> and <<packaging_deployment>> defines how applications that use the services defined by this specification must be packaged into bean archives, and the responsibilities of the container implementation at application initialization time.

<<spi>>, <<contextual>> and <<context>> define an SPI that allows portable extensions to integrate with the container.
<<spi>>, <<spi_lite>>, <<contextual>> and <<context>> define an SPI that allows portable extensions to integrate with the container.

=== Relationship to other specifications

Expand Down Expand Up @@ -550,6 +552,11 @@ The invocation will proceed to the `DocumentEditor` class only if the authorizat

==== Decorator example

[NOTE]
====
Decorators are only available in {cdi_full}.
====

_Decorators_ are similar to interceptors, but apply only to beans of a particular Java interface. Like interceptors, decorators may be easily enabled or disabled at deployment time. Unlike interceptors, decorators are aware of the semantics of the intercepted method.

For example, the `DataAccess` interface might be implemented by many beans:
Expand Down
35 changes: 33 additions & 2 deletions spec/src/main/asciidoc/cdi-spec.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
ifdef::backend-pdf[]
:pagenums:
endif::[]
:cdi_lite: CDI Lite
:cdi_full: CDI Full



Expand All @@ -31,6 +33,10 @@ include::architecture.asciidoc[]
[[part_1]]
= Part I - Core CDI

== {cdi_lite}

:leveloffset: +1

include::core/definition.asciidoc[]

include::core/implementation.asciidoc[]
Expand All @@ -43,16 +49,41 @@ include::core/scopescontexts.asciidoc[]

include::core/lifecycle.asciidoc[]

include::core/decorators.asciidoc[]

include::core/interceptors.asciidoc[]

include::core/events.asciidoc[]

include::core/beanmanager_lite.asciidoc[]

include::core/spi_lite.asciidoc[]

include::core/packagingdeployment_lite.asciidoc[]

:leveloffset: -1

== {cdi_full}

:leveloffset: +1

include::core/definition_full.asciidoc[]

include::core/inheritance_full.asciidoc[]

include::core/injectionandresolution_full.asciidoc[]

include::core/scopescontexts_full.asciidoc[]

include::core/interceptors_full.asciidoc[]

include::core/decorators.asciidoc[]

include::core/events_full.asciidoc[]

include::core/spi.asciidoc[]

include::core/packagingdeployment.asciidoc[]

:leveloffset: -1

[[part_2]]
= Part II - CDI in Java SE
Expand Down
268 changes: 268 additions & 0 deletions spec/src/main/asciidoc/core/beanmanager_lite.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
[[programmatic_access]]

== Programmatic access to container

The `BeanContainer` and `BeanManager` interfaces allow programmatic access to the CDI container.

`BeanContainer` provides features that can be implemented in more restricted environments.
It is available in {cdi_lite} environment, and therefore also in {cdi_full} environment.

`BeanManager` extends `BeanContainer` and provides additional features.
It is only available in {cdi_full} environment.

In {cdi_lite} environment, attempting to obtain a `BeanManager` or invoking methods on it results in non-portable behavior.

[[beancontainer]]

=== The `BeanContainer` object

The interface `jakarta.enterprise.inject.spi.BeanContainer` provides operations for obtaining contextual references for beans, along with many other operations of use to applications.

The container provides a built-in bean with bean type `BeanContainer`, scope `@Dependent` and qualifier `@Default`.
Thus, any bean may obtain an instance of `BeanContainer` by injecting it:

[source, java]
----
@Inject BeanContainer container;
----

The operations of `BeanContainer` may be called at any time during the execution of the application.
// TODO Full has restrictions on when BeanManager methods can be called, do we want to reflect them here in some way?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we instead change the The BeanManager object and mention that those rules apply to both, BM and BeanContainer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be implied by

In {cdi_full} environment, BeanContainer is subject to the same rules as BeanManager.

What I'm more thinking about here is: if we're saying that in Lite, BeanContainer can be invoked at any time, that's a superset of what's allowed in Full. Which might be problematic at least from the "Lite is a strict subset of Full" perspective.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or at least, it might look like a superset. That will depend on how we define the container lifecycle in Lite, which isn't there yet. (In Full, it's defined in the SPI section.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BeanContainer can be invoked at any time

That's not what you wrote there though. You stated ... at any time during the execution of the application which means after the CDI container is bootstrapped, doesn't it? In other words, in Lite you cannot even try to use BeanContainer earlier.
And so long as you cannot use BeanContainer where you couldn't use BM (from within extensions), you should be good.

Or am I missing something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, "at any time during the execution of the application" depends on how we define lifecycle, which we didn't do yet. If we define it in a way that all initialization phases are considered before application execution, then sure.

I added the TODO here mainly as a reminder, to revisit this section after we define lifecycle. I could have worded it more explicitly, for sure -- sorry about that.


[[provider]]

==== Obtaining a reference to the CDI container

Application objects sometimes interact directly with the container via programmatic API call.
The abstract class `jakarta.enterprise.inject.spi.CDI` provides access to the `BeanContainer` as well providing lookup of bean instances.

[source, java]
----
public abstract class CDI<T> implements Instance<T> {
public static CDI<Object> current() { ... }
public static void setCDIProvider(CDIProvider provider);
public abstract BeanContainer getBeanContainer();
public abstract BeanManager getBeanManager();
}
----

An object may obtain a reference to the current container by calling `CDI.current()`.
`CDI.getBeanContainer()`, as well as other methods on `CDI`, may be called after the application initialization is completed until the application shutdown starts.
If methods on `CDI` are called at any other time, non-portable behavior results.

`CDI` implements `jakarta.enterprise.inject.Instance` and therefore might be used to perform programmatic lookup as defined in <<dynamic_lookup>>.
If no qualifier is passed to `CDI.select()` method, the `@Default` qualifier is assumed.

When `CDI.current()` is called, `getCDI()` method is called on `jakarta.enterprise.inject.spi.CDIProvider`.

The `CDIProvider` to use may be set by the application or container using the `setCDIProvider()` method.
If the `setCDIProvider()` has not been called, the service provider with highest priority of the service `jakarta.enterprise.inject.spi.CDIProvider` declared in META-INF/services is used.
The order of more than one `CDIProvider` with the same priority is undefined.
If no provider is available an `IllegalStateException` is thrown.

[source, java]
----
public interface CDIProvider extends Prioritized {
CDI<Object> getCDI();
default int getPriority();
}
----

* `getPriority()` method is inherited from <<prioritized, `Prioritized` interface>> and returns the priority for the `CDIProvider`.
If this method is not implemented the default priority `0` is assumed.


[[bm_obtain_contextual_reference]]

==== Obtaining a contextual reference for a bean

The method `BeanContainer.getReference()` returns a contextual reference for a given bean and bean type, as defined in <<contextual_reference>>.

[source, java]
----
public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx);
----

The first parameter is the `Bean` object representing the bean.
The second parameter represents a bean type that must be implemented by any client proxy that is returned.
The third parameter is an instance of `CreationalContext` that may be used to destroy any object with scope `@Dependent` that is created.

If the given type is not a bean type of the given bean, an `IllegalArgumentException` is thrown.

[[bm_obtain_injectable_reference]]

==== Obtaining an injectable reference

The method `BeanContainer.getInjectableReference()` returns an injectable reference for a given injection point, as defined in <<injectable_reference>>.

[source, java]
----
public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx);
----

The first parameter represents the target injection point.
The second parameter is an instance of `CreationalContext` that may be used to destroy any object with scope `@Dependent` that is created.

If typesafe resolution results in an unsatisfied dependency, the container must throw an `UnsatisfiedResolutionException`. If typesafe resolution results in an unresolvable ambiguous dependency, the container must throw an `AmbiguousResolutionException`.

Implementations of `Bean` usually maintain a reference to an instance of `BeanContainer`. When the `Bean` implementation performs dependency injection, it must obtain the contextual instances to inject by calling `BeanContainer.getInjectableReference()`, passing an instance of `InjectionPoint` that represents the injection point and the instance of `CreationalContext` that was passed to `Bean.create()`.

[[bm_obtain_creationalcontext]]

==== Obtaining a `CreationalContext`

An instance of `CreationalContext` for a certain instance of `Contextual` may be obtained by calling `BeanContainer.createCreationalContext()`.

[source, java]
----
public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual);
----

An instance of `CreationalContext` for a non-contextual object may be obtained by passing a null value to `createCreationalContext()`.

[[bm_obtain_bean_by_type]]

==== Obtaining a `Bean` by type

The method `BeanContainer.getBeans()` returns the set of beans which have the given required type and qualifiers and are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules for candidates of typesafe resolution defined in <<performing_typesafe_resolution>>.

[source, java]
----
public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers);
----

The first parameter is a required bean type. The remaining parameters are required qualifiers.

If no qualifiers are passed to `getBeans()`, the default qualifier `@Default` is assumed.

If the given type represents a type variable, an `IllegalArgumentException` is thrown.

If two instances of the same non repeating qualifier type are given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not a qualifier type is given, an `IllegalArgumentException` is thrown.

[[bm_obtain_bean_by_name]]

==== Obtaining a `Bean` by name

The method `BeanContainer.getBeans()` which accepts a string returns the set of beans which have the given bean name and are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules of name resolution defined in <<name_resolution>>.

[source, java]
----
public Set<Bean<?>> getBeans(String name);
----

The parameter is a bean name.

[[bm_resolve_ambiguous_dep]]

==== Resolving an ambiguous dependency

The method `BeanContainer.resolve()` applies the ambiguous dependency resolution rules defined in <<unsatisfied_and_ambig_dependencies>> to a set of `Bean` s.

[source, java]
----
public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans);
----

If the ambiguous dependency resolution rules fail (as defined in <<unsatisfied_and_ambig_dependencies>>, the container must throw an `AmbiguousResolutionException`.

`BeanContainer.resolve()` must return null if:

* null is passed to `resolve()`, or
* no beans are passed to `resolve()`.

[[bm_fire_event]]

==== Firing an event

The method `BeanContainer.getEvent()` returns an instance of `Event` with specified type `java.lang.Object` and specified qualifier `@Default`.

[source, java]
----
Event<Object> getEvent();
----

The returned instance can be used like a standard `Event` as described in <<events>>.

[[bm_observer_method_resolution]]

==== Observer method resolution

The method `BeanContainer.resolveObserverMethods()` resolves observer methods for an event according to the rules of observer resolution defined in <<observer_resolution>>.

[source, java]
----
public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers);
----

The first parameter of `resolveObserverMethods()` is the event object.
The remaining parameters are event qualifiers.

If the runtime type of the event object contains a type variable, an `IllegalArgumentException` is thrown.

If two instances of the same non repeating qualifier type are given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not a qualifier type is given, an `IllegalArgumentException` is thrown.

[[bm_interceptor_resolution]]

==== Interceptor resolution

The method `BeanContainer.resolveInterceptors()` returns the ordered list of interceptors for a set of interceptor bindings and a type of interception and which are enabled in the module or library containing the class into which the `BeanContainer` was injected, as defined in <<interceptor_resolution>>.

[source, java]
----
List<Interceptor<?>> resolveInterceptors(InterceptionType type,
Annotation... interceptorBindings);
----

If two instances of the same non repeating interceptor binding type are given, an `IllegalArgumentException` is thrown.

If no interceptor binding type instance is given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not an interceptor binding type is given, an `IllegalArgumentException` is thrown.

[[bm_determining_annotation]]

==== Determining if an annotation is a qualifier type, scope type, stereotype or interceptor binding type

An application may test an annotation to determine if it is a qualifier type, scope type, stereotype or interceptor binding type, or determine if a scope type is a normal scope.

[source, java]
----
public boolean isScope(Class<? extends Annotation> annotationType);
public boolean isNormalScope(Class<? extends Annotation> scopeType);

public boolean isQualifier(Class<? extends Annotation> annotationType);
public boolean isInterceptorBinding(Class<? extends Annotation> annotationType);
public boolean isStereotype(Class<? extends Annotation> annotationType);
----

[[bm_obtain_active_context]]

==== Obtaining the active `Context` for a scope

The method `BeanContainer.getContext()` retrieves an active context object associated with the given scope, as defined in <<active_context>>.

[source, java]
----
public Context getContext(Class<? extends Annotation> scopeType);
----

[[bm_obtain_instance]]

==== Obtain an `Instance`

The method `BeanContainer.createInstance()` returns an `Instance<Object>` to request bean instances programmatically as described in <<dynamic_lookup>>.

The returned `Instance` object can only access instances of beans that are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules defined in <<typesafe_resolution>>.

[source, java]
----
Instance<Object> createInstance();
----

Instances of dependent scoped beans obtained with this `Instance` object must be explicitly released by calling `Instance.destroy()` method.

If no qualifier is passed to `Instance.select()` method, the `@Default` qualifier is assumed.