Skip to content

Latest commit

 

History

History
839 lines (546 loc) · 41.1 KB

injectionandresolution.asciidoc

File metadata and controls

839 lines (546 loc) · 41.1 KB

Dependency injection and lookup

The container injects references to contextual instances to the following kinds of injection point:

  • Any injected field of a bean class

  • Any parameter of a bean constructor, bean initializer method, producer method or disposer method

  • Any parameter of an observer method, except for the event parameter

References to contextual instances may also be obtained by programmatic lookup.

In general, a bean type or bean name does not uniquely identify a bean. When resolving a bean at an injection point, the container considers bean type, qualifiers and selected alternatives. This allows bean developers to decouple type from implementation.

The container is required to support circularities in the bean dependency graph where at least one bean participating in every circular chain of dependencies has a normal scope, as defined in [normal_scope]. The container is not required to support circular chains of dependencies where every bean participating in the chain has a pseudo-scope.

Modularity

Beans and their clients may be deployed in modules in a module architecture. In a module architecture, certain modules are considered bean archives. The library may be an explicit bean archive or an implicit bean archive, as defined in [bean_archive]. In {cdi_lite}, libraries that are bean archives are always implicit bean archives.

A bean packaged in a certain module is available for injection, lookup and name resolution to classes packaged in some other module if and only if the bean class of the bean is required to be accessible to the other module by the class accessibility requirements of the module architecture.

An alternative is not available for injection, lookup or name resolution to classes in a module unless the module is a bean archive and the alternative is explicitly selected for the application.

Declaring selected alternatives

{cdi_lite} defines one method of selecting alternatives: the @Priority annotation allows an alternative to be selected for an entire application. {cdi_full} defines an additional method of selecting alternatives, which is specified therein.

Declaring selected alternatives for an application

An alternative may be given a priority for the application:

  • by placing the @Priority annotation on the bean class of a managed bean, or

  • by placing the @Priority annotation on the bean class that declares the producer method, field or resource.

Custom bean implementations which are also alternatives may implement Prioritized interface in which case they will be enabled for entire application with given priority.

Enabled and disabled beans

A bean is said to be enabled if:

  • it is deployed in a bean archive, and

  • it is not a producer method or field of a disabled bean, and either

  • it is not an alternative, or it is a selected alternative for the application.

Otherwise, the bean is said to be disabled.

Inter-module injection

A bean is available for injection in a certain module if:

  • the bean is not an interceptor

  • the bean is enabled,

  • the bean is either not an alternative, or the module is a bean archive and the bean is a selected alternative for the application, and

  • the bean class is required to be accessible to classes in the module, according to the class accessibility requirements of the module architecture.

Typesafe resolution

The process of matching a bean to an injection point is called typesafe resolution. Typesafe resolution usually occurs at application initialization time, allowing the container to warn the user if any enabled beans have unsatisfied or unresolvable ambiguous dependencies.

Performing typesafe resolution

The container considers bean type and qualifiers when resolving a bean to be injected to an injection point. The type and qualifiers of the injection point are called the required type and required qualifiers.

A bean is assignable to a given injection point if:

  • The bean has a bean type that matches the required type. For this purpose, primitive types are considered to match their corresponding wrapper types in java.lang and array types are considered to match only if their element types are identical. Parameterized and raw types are considered to match if they are identical or if the bean type is assignable to the required type, as defined in Assignability of raw and parameterized types.

  • The bean has all the required qualifiers. If no required qualifiers were explicitly specified, the container assumes the required qualifier @Default. A bean has a required qualifier if it has a qualifier with (a) the same type and (b) the same annotation member value for each member which is not annotated @jakarta.enterprise.util.Nonbinding.

A bean is eligible for injection to a certain injection point if:

For a custom implementation of the Bean interface defined in [bean], the container calls getTypes() and getQualifiers() to determine the bean types and qualifiers.

Unsatisfied and ambiguous dependencies

An unsatisfied dependency exists at an injection point when no bean is eligible for injection to the injection point. An ambiguous dependency exists at an injection point when multiple beans are eligible for injection to the injection point.

When an ambiguous dependency exists, the container attempts to resolve the ambiguity. The container eliminates all eligible beans that are not alternatives selected for the application, except for producer methods and fields of beans that are alternatives. If:

  • there is exactly one bean remaining, the container will select this bean, and the ambiguous dependency is called resolvable.

  • all the beans left are alternatives with a priority, or producer methods or fields of beans that are alternatives with a priority, then the container will determine the highest priority value, and eliminate all beans, except for alternatives with the highest priority and producer methods and fields of alternatives with the highest priority value. If there is exactly one bean remaining, the container will select this bean, and the ambiguous dependency is called resolvable.

The container must validate all injection points of all enabled beans, all observer methods and all disposer methods when the application is initialized to ensure that there are no unsatisfied or unresolvable ambiguous dependencies. If an unsatisfied or unresolvable ambiguous dependency exists, the container automatically detects the problem and treats it as a deployment problem.

For a custom implementation of the Bean interface defined in [bean], the container calls getInjectionPoints() to determine the set of injection points.

Any legal bean type, as defined in [legal_bean_types] may be the required type of an injection point. Furthermore, the required type of an injection point may contain a wildcard type parameter. However, a type variable is not a legal injection point type.

If an injection point type is a type variable, the container automatically detects the problem and treats it as a definition error.

Assignability of raw and parameterized types

A parameterized bean type is considered assignable to a raw required type if the raw types are identical and all type parameters of the bean type are either unbounded type variables or java.lang.Object.

A parameterized bean type is considered assignable to a parameterized required type if they have identical raw type and for each parameter:

  • the required type parameter and the bean type parameter are actual types with identical raw type, and, if the type is parameterized, the bean type parameter is assignable to the required type parameter according to these rules, or

  • the required type parameter is a wildcard, the bean type parameter is an actual type and the actual type is assignable to the upper bound, if any, of the wildcard and assignable from the lower bound, if any, of the wildcard, or

  • the required type parameter is a wildcard, the bean type parameter is a type variable and the upper bound of the type variable is assignable to or assignable from the upper bound, if any, of the wildcard and assignable from the lower bound, if any, of the wildcard, or

  • the required type parameter is an actual type, the bean type parameter is a type variable and the actual type is assignable to the upper bound, if any, of the type variable, or

  • the required type parameter and the bean type parameter are both type variables and the upper bound of the required type parameter is assignable to the upper bound, if any, of the bean type parameter.

For example, Dao is eligible for injection to any injection point of type @Default Dao<Order>, @Default Dao<User>, @Default Dao<?>, @Default Dao<? extends Persistent> or @Default Dao<X extends Persistent> where X is a type variable.

public class Dao<T extends Persistent> { ... }

Furthermore, UserDao is eligible for injection to any injection point of type @Default Dao<User>, @Default Dao<?>, @Default Dao<? extends Persistent> or @Default Dao<? extends User>.

public class UserDao extends Dao<User> { ... }

A raw bean type is considered assignable to a parameterized required type if the raw types are identical and all type parameters of the required type are either unbounded type variables or java.lang.Object.

Primitive types and null values

For the purposes of typesafe resolution and dependency injection, primitive types and their corresponding wrapper types in the package java.lang are considered identical and assignable. If necessary, the container performs boxing or unboxing when it injects a value to a field or parameter of primitive or wrapper type.

If an injection point of primitive type resolves to a producer method or producer field that returns a null value at runtime, the container must inject the primitive type’s default value as defined by the Java Language Specification.

Qualifier annotations with members

Qualifier types may have annotation members.

@PayBy(CHEQUE) class ChequePaymentProcessor implements PaymentProcessor { ... }
@PayBy(CREDIT_CARD) class CreditCardPaymentProcessor implements PaymentProcessor { ... }

Then only ChequePaymentProcessor is a candidate for injection to the following attribute:

@Inject @PayBy(CHEQUE) PaymentProcessor paymentProcessor;

On the other hand, only CreditCardPaymentProcessor is a candidate for injection to this attribute:

@Inject @PayBy(CREDIT_CARD) PaymentProcessor paymentProcessor;

The container calls the equals() method of the annotation member value to compare values.

An annotation member may be excluded from consideration using the @Nonbinding annotation.

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface PayBy {
    PaymentMethod value();
    @Nonbinding String comment() default "";
}

Array-valued or annotation-valued members of a qualifier type should be annotated @Nonbinding in a portable application. If an array-valued or annotation-valued member of a qualifier type is not annotated @Nonbinding, non-portable behavior results.

Multiple qualifiers

A bean class or producer method or field may declare multiple qualifiers.

@Synchronous @PayBy(CHEQUE) class ChequePaymentProcessor implements PaymentProcessor { ... }

Then ChequePaymentProcessor would be considered a candidate for injection into any of the following attributes:

@Inject @PayBy(CHEQUE) PaymentProcessor paymentProcessor;
@Inject @Synchronous PaymentProcessor paymentProcessor;
@Inject @Synchronous @PayBy(CHEQUE) PaymentProcessor paymentProcessor;

A bean must declare all of the qualifiers that are specified at the injection point to be considered a candidate for injection.

Name resolution

The process of matching a bean to a name is called name resolution. Since there is no typing information available during name resolution, the container may consider only the bean name. Name resolution usually occurs at runtime.

A name resolves to a bean if:

  • the bean has the given bean name, and

  • the bean is available for injection in the module where the name resolution is requested.

For a custom implementation of the Bean interface defined in [bean], the container calls getName() to determine the bean name.

Ambiguous names

An ambiguous name exists when a name resolves to multiple beans. When an ambiguous name exists, the container attempts to resolve the ambiguity. The container eliminates all eligible beans that are not alternatives selected for the application, except for producer methods and fields of beans that are alternatives. If:

  • there is exactly one bean remaining, the container will select this bean, and the ambiguous dependency is called resolvable.

  • all the beans left are alternatives with a priority, then the container will determine the highest priority value, and eliminate all beans, except for producer methods and fields of beans that are alternatives with the highest priority value. If there is exactly one bean remaining, the container will select this bean, and the ambiguous dependency is called resolvable.

All unresolvable ambiguous names are detected by the container when the application is initialized. Suppose two beans are both available for injection in a certain module, and either:

  • the two beans have the same bean name and the name is not resolvable, or

  • the bean name of one bean is of the form x.y, where y is a valid bean name, and x is the bean name of the other bean,

the container automatically detects the problem and treats it as a deployment problem.

Client proxies

An injected reference, or reference obtained by programmatic lookup, is usually a contextual reference as defined by [contextual_reference].

A contextual reference to a bean with a normal scope, as defined in [normal_scope], is not a direct reference to a contextual instance of the bean (the object returned by Contextual.create()). Instead, the contextual reference is a client proxy object. A client proxy implements/extends some or all of the bean types of the bean and delegates all method calls to the current instance (as defined in [normal_scope]) of the bean.

There are a number of reasons for this indirection:

  • The container must guarantee that when any valid injected reference to a bean of normal scope is invoked, the invocation is always processed by the current instance of the injected bean. In certain scenarios, for example if a request scoped bean is injected into a session scoped bean, or into a servlet, this rule requires an indirect reference. (Note that the @Dependent pseudo-scope is not a normal scope.)

  • The container may use a client proxy when creating beans with circular dependencies. This is only necessary when the circular dependencies are initialized via a managed bean constructor or producer method parameter. (Beans with scope @Dependent never have circular dependencies.)

  • Finally, client proxies may be passivated, even when the bean itself may not be. Therefore the container must use a client proxy whenever a bean with normal scope is injected into a bean with a passivating scope, as defined in [passivating_scope]. (On the other hand, beans with scope @Dependent must be serialized along with their client.)

Client proxies are never required for a bean whose scope is a pseudo-scope such as @Dependent.

Client proxies may be shared between multiple injection points. For example, a particular container might instantiate exactly one client proxy object per bean. (However, this strategy is not required by this specification.)

Client proxy invocation

Every time a method of the bean is invoked upon a client proxy, the client proxy must:

  • obtain a contextual instance of the bean, as defined in [contextual_instance], and

  • invoke the method upon this instance.

If the scope is not active, as specified in [active_context], the client proxy rethrows the ContextNotActiveException or IllegalStateException.

The behavior of all methods declared by java.lang.Object, except for toString(), is undefined for a client proxy. Portable applications should not invoke any method declared by java.lang.Object, except for toString(), on a client proxy.

Dependency injection

From time to time the container instantiates beans and other class supporting injection. The resulting instance may or may not be a contextual instance as defined by [contextual_instance].

The container is required to perform dependency injection whenever it creates the following contextual objects:

  • contextual instances of managed beans.

The container is also required to perform dependency injection whenever it instantiates the following non-contextual objects:

  • non-contextual instances of managed beans.

The container interacts with instances of beans or objects supporting injection by calling methods and getting and setting field values.

The object injected by the container may not be a direct reference to a contextual instance of the bean. Instead, it is an injectable reference, as defined by [injectable_reference].

Injection using the bean constructor

When the container instantiates a managed bean with a constructor annotated @Inject, the container calls this constructor, passing an injectable reference to each parameter. If there is no constructor annotated @Inject, the container calls the constructor with no parameters.

Injection of fields and initializer methods

When the container creates a new instance of a managed bean, the container must:

  • Initialize the values of all injected fields. The container sets the value of each injected field to an injectable reference.

  • Call all initializer methods, passing an injectable reference to each parameter.

The container must ensure that:

  • Initializer methods declared by a class X in the type hierarchy of the bean are called after all injected fields declared by X or by superclasses of X have been initialized.

  • Any @PostConstruct callback declared by a class X in the type hierarchy of the bean is called after all initializer methods declared by X or by superclasses of X have been called, after all injected fields declared by X or by superclasses of X have been initialized.

Destruction of dependent objects

When the container destroys an instance of a bean, the container destroys all dependent objects, as defined in [dependent_destruction], after the @PreDestroy callback completes.

Invocation of producer or disposer methods

When the container calls a producer or disposer method, the behavior depends upon whether the method is static or non-static:

  • If the method is static, the container must invoke the method.

  • Otherwise, if the method is non-static, the container must:

  • Obtain a contextual instance of the bean which declares the method, as defined by [contextual_instance].

  • Invoke the method upon this instance, as a business method invocation, as defined in [biz_method].

The container passes an injectable reference to each injected method parameter. The container is also responsible for destroying dependent objects created during this invocation, as defined in [dependent_destruction].

Access to producer field values

When the container accesses the value of a producer field, the value depends upon whether the field is static or non-static:

  • If the producer field is static, the container must access the field value.

  • Otherwise, if the producer field is non-static, the container must:

  • Obtain an contextual instance of the bean which declares the producer field, as defined by [contextual_instance].

  • Access the field value of this instance.

Invocation of observer methods

When the container calls an observer method (defined in [observer_methods]), the behavior depends upon whether the method is static or non-static:

  • If the observer method is static, the container must invoke the method.

  • Otherwise, if the observer method is non-static, the container must:

  • Obtain a contextual instance of the bean which declares the observer method according to [contextual_instance]. If this observer method is a conditional observer method, obtain the contextual instance that already exists, only if the scope of the bean that declares the observer method is currently active, without creating a new contextual instance.

  • Invoke the observer method on the resulting instance, if any, as a business method invocation, as defined in [biz_method].

The container must pass the event object to the event parameter and an injectable instance to each injected method parameter. The container is also responsible for destroying dependent objects created during this invocation, as defined in [dependent_destruction].

Injection point metadata

The interface jakarta.enterprise.inject.spi.InjectionPoint provides access to metadata about an injection point. An instance of InjectionPoint may represent:

  • an injected field or a parameter of a bean constructor, initializer method, producer method, disposer method or observer method, or

  • an instance obtained dynamically using Instance.get().

public interface InjectionPoint {
    public Type getType();
    public Set<Annotation> getQualifiers();
    public Bean<?> getBean();
    public Member getMember();
    public Annotated getAnnotated();
    public boolean isDelegate();
    public boolean isTransient();
}
  • The getBean() method returns the Bean object representing the bean that defines the injection point. If the injection point does not belong to a bean, getBean() returns a null value. If the injection point represents a dynamically obtained instance, the getBean() method should return the Bean object representing the bean that defines the Instance injection point.

  • The getType() and getQualifiers() methods return the required type and required qualifiers of the injection point. If the injection point represents a dynamically obtained instance, the getType() and getQualifiers() methods should return the required type (as defined by Instance.select()), and required qualifiers of the injection point including any additional required qualifiers (as defined by Instance.select()).

  • The getMember() method returns the Field object in the case of field injection, the Method object in the case of method parameter injection, or the Constructor object in the case of constructor parameter injection. If the injection point represents a dynamically obtained instance, the getMember() method returns the Field object representing the field that defines the Instance injection point in the case of field injection, the Method object representing the method that defines the Instance injection point in the case of method parameter injection, or the Constructor object representing the constructor that defines the Instance injection point in the case of constructor parameter injection.

  • The getAnnotated() method may, in {cdi_lite} environment, always return null. Behavior of this method in {cdi_full} is specified therein.

  • The isDelegate() method may, in {cdi_lite} environment, always return false. Behavior of this method in {cdi_full} is specified therein.

  • The isTransient() method returns true if the injection point is a transient field, and false otherwise. If the injection point represents a dynamically obtained instance then the isTransient() method returns true if the Instance injection point is a transient field, and false otherwise. If this injection point is declared as transient, after bean’s passivation, the value will not be restored. Instance<> injection point is the preferred approach.

Occasionally, a bean with scope @Dependent needs to access metadata relating to the object into which it is injected. For example, the following producer method creates injectable Logger s. The log category of a Logger depends upon the class of the object into which it is injected:

@Produces Logger createLogger(InjectionPoint injectionPoint) {
    return Logger.getLogger( injectionPoint.getMember().getDeclaringClass().getName() );
}

The container must provide a bean with scope @Dependent, bean type InjectionPoint and qualifier @Default, allowing dependent objects, as defined in [dependent_objects], to obtain information about the injection point to which they belong. The built-in implementation must be a passivation capable dependency, as defined in [passivation_capable_dependency].

If a bean that declares any scope other than @Dependent has an injection point of type InjectionPoint and qualifier @Default, the container automatically detects the problem and treats it as a definition error.

If a disposer method has an injection point of type InjectionPoint and qualifier Default, the container automatically detects the problem and treats it as a definition error.

If a class supporting injection that is not a bean has an injection point of type InjectionPoint and qualifier @Default, the container automatically detects the problem and treats it as a definition error.

Bean metadata

The interfaces Bean and Interceptor provide metadata about a bean.

The container must provide beans allowing a bean instance to obtain a Bean or Interceptor instance containing its metadata:

  • a bean with scope @Dependent, qualifier @Default and type Bean which can be injected into any bean instance

  • a bean with scope @Dependent, qualifier @Default and type Interceptor which can be injected into any interceptor instance

Additionally, the container must provide beans allowing interceptors to obtain information about the beans they intercept:

  • a bean with scope @Dependent, qualifier @Intercepted and type Bean which can be injected into any interceptor instance.

These beans are passivation capable dependencies, as defined in [passivation_capable_dependency].

If an Interceptor instance is injected into a bean instance other than an interceptor instance, the container automatically detects the problem and treats it as a definition error.

If a Bean instance with qualifier @Intercepted is injected into a bean instance other than an interceptor instance, the container automatically detects the problem and treats it as a definition error.

The injection of bean metadata is restricted. If:

  • the injection point is a field, an initializer method parameter or a bean constructor, with qualifier @Default, then the type parameter of the injected Bean, or Interceptor must be the same as the type declaring the injection point, or

  • the injection point is a field, an initializer method parameter or a bean constructor of an interceptor, with qualifier @Intercepted, then the type parameter of the injected Bean must be an unbounded wildcard, or

  • the injection point is a producer method parameter then the type parameter of the injected Bean must be the same as the producer method return type, or

  • the injection point is a parameter of a disposer method then the container automatically detects the problem and treats it as a definition error.

Otherwise, the container automatically detects the problem and treats it as a definition error.

@Named("Order") public class OrderProcessor {

    @Inject Bean<OrderProcessor> bean;

    public void getBeanName() {
       return bean.getName();
    }

}

Programmatic lookup

In certain situations, injection is not the most convenient way to obtain a contextual reference. For example, it may not be used when:

  • the bean type or qualifiers vary dynamically at runtime, or

  • depending upon the deployment, there may be no bean which satisfies the type and qualifiers, or

  • we would like to iterate over all beans of a certain type.

In these situations, an instance of the jakarta.enterprise.inject.Instance interface may be injected:

@Inject Instance<PaymentProcessor> paymentProcessor;

The method get() returns a contextual reference:

PaymentProcessor pp = paymentProcessor.get();

Any combination of qualifiers may be specified at the injection point:

@Inject @PayBy(CHEQUE) Instance<PaymentProcessor> chequePaymentProcessor;

Or, the @Any qualifier may be used, allowing the application to specify qualifiers dynamically:

@Inject @Any Instance<PaymentProcessor> anyPaymentProcessor;
...
Annotation qualifier = synchronously ? new SynchronousQualifier() : new AsynchronousQualifier();
PaymentProcessor pp = anyPaymentProcessor.select(qualifier).get().process(payment);

In this example, the returned bean has qualifier @Synchronous or @Asynchronous depending upon the value of synchronously.

It’s even possible to iterate over a set of beans:

@Inject @Any Instance<PaymentProcessor> anyPaymentProcessor;
...
for (PaymentProcessor pp: anyPaymentProcessor) pp.test();

The Instance interface

The Instance interface provides a method for obtaining instances of beans with a specified combination of required type and qualifiers, and inherits the ability to iterate beans with that combination of required type and qualifiers from java.lang.Iterable:

public interface Instance<T> extends Iterable<T>, Provider<T> {

    Instance<T> select(Annotation... qualifiers);
    <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers);
    <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers);

    Stream<T> stream();

    boolean isUnsatisfied();
    boolean isAmbiguous();
    boolean isResolvable();

    void destroy(T instance);

    Handle<T> getHandle();
    Iterable<Handle<T>> handles();
    Stream<Handle<T>> handlesStream();

}

For an injected Instance:

  • the required type is the type parameter specified at the injection point, and

  • the required qualifiers are the qualifiers specified at the injection point.

For example, this injected Instance has required type PaymentProcessor and required qualifier @Any:

@Inject @Any Instance<PaymentProcessor> anyPaymentProcessor;

The select() method returns a child Instance for a given required type and additional required qualifiers. If no required type is given, the required type is the same as the parent. Rules specified at [injection_point_default_qualifier] are applied before performing typesafe resolution.

For example, this child Instance has required type AsynchronousPaymentProcessor and additional required qualifier @Asynchronous:

Instance<AsynchronousPaymentProcessor> async = anyPaymentProcessor.select(
            AsynchronousPaymentProcessor.class, new AsynchronousQualifier() );

If an injection point of raw type Instance is defined, the container automatically detects the problem and treats it as a definition error.

If two instances of the same non repeating qualifier type are passed to select(), an IllegalArgumentException is thrown.

If an instance of an annotation that is not a qualifier type is passed to select(), an IllegalArgumentException is thrown.

The get() method must:

  • Identify a bean that has the required type and required qualifiers and is eligible for injection into the class into which the parent Instance was injected, according to the rules of typesafe resolution, as defined in Performing typesafe resolution, resolving ambiguities according to Unsatisfied and ambiguous dependencies.

  • If typesafe resolution results in an unsatisfied dependency, throw an UnsatisfiedResolutionException. If typesafe resolution results in an unresolvable ambiguous dependency, throw an AmbiguousResolutionException.

  • Otherwise, obtain a contextual reference for the bean and the required type, as defined in [contextual_reference].

The iterator() method must:

  • Identify the set of beans that have the required type and required qualifiers and are eligible for injection into the class into which the parent Instance was injected, according to the rules of typesafe resolution, as defined in Performing typesafe resolution, resolving ambiguities according to Unsatisfied and ambiguous dependencies.

  • Return an Iterator, that iterates over the set of contextual references for the resulting beans and required type, as defined in [contextual_reference].

The stream() method must:

  • Identify the set of beans that have the required type and required qualifiers and are eligible for injection into the class into which the parent Instance was injected, according to the rules of typesafe resolution, as defined in Performing typesafe resolution, resolving ambiguities according to Unsatisfied and ambiguous dependencies.

  • Return a Stream, that can stream over the set of contextual references for the resulting beans and required type, as defined in [contextual_reference].

The methods isUnsatisfied(), isAmbiguous() and isResolvable() must:

  • Identify the set of beans that have the required type and required qualifiers and are eligible for injection into the class into which the parent Instance was injected, according to the rules of typesafe resolution, as defined in Performing typesafe resolution, resolving ambiguities according to Unsatisfied and ambiguous dependencies.

  • The method isUnsatisfied() returns true if there is no bean found, or false otherwise.

  • The method isAmbiguous() returns true if there is more than one bean found, or false otherwise.

  • The method isResolvable() returns true if there is exactly one bean found, or false otherwise.

The method destroy() instructs the container to destroy the instance. The bean instance passed to destroy() should be a dependent scoped bean instance obtained from the same Instance object, or a client proxy for a normal scoped bean. Applications are encouraged to always call destroy() when they no longer require an instance obtained from Instance. All built-in normal scoped contexts support destroying bean instances. An UnsupportedOperationException is thrown if the active context object for the scope type of the bean does not support destroying bean instances.

The getHandle() method must:

  • Return an initialized contextual reference Handle<T> for a bean that has the required type and qualifiers and is eligible for injection. The contextual reference must be resolved lazily, i.e. when first needed. The Handle interface is described in a separate paragraph.

  • Throw UnsatisfiedResolutionException if there is no bean with given type and qualifiers

  • Throw AmbiguousResolutionException if there is more than one bean given type and qualifiers

The handles() method must:

  • Allow iterating over contextual reference handles for all beans that have the required type and required qualifiers and are eligible for injection.

  • Return stateless Iterable. Therefore, each Iterable#iterator() produces a new set of handles.

The handlesStream() is a Stream equivalent of the aforementioned handles() method.

The Handle interface

Handle is an interface representing a contextual reference handle. It is an abstraction allowing inspection of bean metadata via Bean<?> objects. Handles have to resolve their contextual references lazily, i.e. when their get() method is invoked. Last but not least, this interface can be used to destroy the contextual instance once not needed.

public interface Handle<T> extends AutoCloseable {

        T get();
        Bean<T> getBean();
        void destroy();
        void close();

}

The get() method returns a contextual reference object. The contextual reference is resolved lazily.

The getBean() method returns the Bean object representing metadata of the given contextual instance.

The destroy() method destroys the contextual instance and is a no-op if:

  • called multiple times

  • the producing Instance does not exist

  • the handle does not hold a contextual reference, i.e. get() was never called

The rules for destroying instances are the same as with Instance#destroy().

The close() method delegates to the aforementioned destroy() method.

The built-in Instance

The container must provide a built-in bean that:

  • is eligible for injection to any injection point with required type Instance<X> or Provider<X>, for any legal bean type X,

  • has any qualifiers

  • has scope @Dependent,

  • has no bean name, and

  • has an implementation provided automatically by the container.

The built-in implementation must be a passivation capable dependency, as defined in [passivation_capable_dependency].

Using AnnotationLiteral and TypeLiteral

jakarta.enterprise.util.AnnotationLiteral makes it easier to specify qualifiers when calling select():

public PaymentProcessor getSynchronousPaymentProcessor(PaymentMethod paymentMethod) {

    class SynchronousQualifier extends AnnotationLiteral<Synchronous>
            implements Synchronous {}

    class PayByQualifier extends AnnotationLiteral<PayBy>
            implements PayBy {
        public PaymentMethod value() { return paymentMethod; }
    }

    return anyPaymentProcessor.select(new SynchronousQualifier(), new PayByQualifier()).get();
}

jakarta.enterprise.util.TypeLiteral makes it easier to specify a parameterized type with actual type parameters when calling select():

public PaymentProcessor<Cheque> getChequePaymentProcessor() {
    PaymentProcessor<Cheque> pp = anyPaymentProcessor
        .select( new TypeLiteral<PaymentProcessor<Cheque>>() {} ).get();
}

Built-in annotation literals

The following built-in annotations define a Literal static nested class to support inline instantiation of the specific annotation type:

  • jakarta.enterprise.inject.Any

  • jakarta.enterprise.inject.Default

  • jakarta.enterprise.inject.Specializes

  • jakarta.enterprise.inject.Vetoed

  • jakarta.enterprise.util.Nonbinding

  • jakarta.enterprise.context.Initialized

  • jakarta.enterprise.context.Destroyed

  • jakarta.enterprise.context.RequestScoped

  • jakarta.enterprise.context.SessionScoped

  • jakarta.enterprise.context.ApplicationScoped

  • jakarta.enterprise.context.Dependent

  • jakarta.enterprise.context.ConversationScoped

  • jakarta.enterprise.inject.Alternative

  • jakarta.enterprise.inject.Typed

The Literal class might be used to instantiate the matching AnnotationLiteral:

Default defaultLiteral = new Default.Literal();

Annotations without members provide the default AnnotationLiteral instance declared as a constant named INSTANCE:

RequestScoped requestScopedLiteral = RequestScoped.Literal.INSTANCE;

Annotations having members do not provide the default AnnotationLiteral instance. Instead, a constructor or factory method named of can be used:

Initialized initializedForApplicationScoped = new Initialized.Literal(ApplicationScoped.class);

Initialized initializedForRequestScoped = Initialized.Literal.of(RequestScoped.class);

See also the annotation javadoc for more information about specific Literal members.

In addition, CDI also provides annotation literals for the following JSR 330 annotations:

  • jakarta.inject.Inject with jakarta.enterprise.inject.literal.InjectLiteral class

  • jakarta.inject.Named with jakarta.enterprise.inject.literal.NamedLiteral class

  • jakarta.inject.Qualifier with jakarta.enterprise.inject.literal.QualifierLiteral class

  • jakarta.inject.Singleton with jakarta.enterprise.inject.literal.SingletonLiteral class

They can be used like static nested classes described above.