Skip to content

Latest commit

 

History

History
1728 lines (1220 loc) · 81.7 KB

spi.asciidoc

File metadata and controls

1728 lines (1220 loc) · 81.7 KB

Portable extensions

A portable extension may integrate with the container by:

  • Providing its own beans, interceptors and decorators to the container

  • Injecting dependencies into its own objects using the dependency injection service

  • Providing a context implementation for a custom scope

  • Augmenting or overriding the annotation-based metadata with metadata from some other source

The Bean interface

The BeanAttributes interface exposes the basic attributes of a bean.

public interface BeanAttributes<T> {
    public Set<Type> getTypes();
    public Set<Annotation> getQualifiers();
    public Class<? extends Annotation> getScope();
    public String getName();
    public Set<Class<? extends Annotation>> getStereotypes();
    public boolean isAlternative();
}
  • getTypes(), getQualifiers(), getScope(), getName() and getStereotypes() must return the bean types, qualifiers, scope type, bean name and stereotypes of the bean, as defined in [concepts].

  • isAlternative() must return true if the bean is an alternative, and false otherwise.

The interface jakarta.enterprise.inject.spi.Bean defines everything the container needs to manage instances of a certain bean.

public interface Bean<T> extends Contextual<T>, BeanAttributes<T> {
    public Class<?> getBeanClass();
    public Set<InjectionPoint> getInjectionPoints();
}
  • getBeanClass() returns the bean class of the managed bean or of the bean that declares the producer method or field.

  • getInjectionPoints() returns a set of InjectionPoint objects, defined in [injection_point], representing injection points of the bean, that will be validated by the container at initialization time.

Note that implementations of Bean must also implement the inherited operations defined by the Contextual interface defined in [contextual].

An instance of Bean must exist for every enabled bean.

A portable extension may add support for new kinds of beans beyond those defined by the this specification by implementing Bean and registering beans with the container, using the mechanism defined in AfterBeanDiscovery event.

Custom implementations of Bean are encouraged to implement PassivationCapable and may be required to in later revisions of this specification.

The Decorator interface

The Bean object for a decorator must implement the interface jakarta.enterprise.inject.spi.Decorator.

public interface Decorator<T> extends Bean<T> {
    public Set<Type> getDecoratedTypes();
    public Type getDelegateType();
    public Set<Annotation> getDelegateQualifiers();
}
  • getDecoratedTypes() returns the decorated types of the decorator.

  • getDelegateType() and getDelegateQualifiers() return the delegate type and qualifiers of the decorator.

An instance of Decorator exists for every enabled decorator.

The Interceptor interface

The Bean object for an interceptor must implement jakarta.enterprise.inject.spi.Interceptor.

public interface Interceptor<T> extends Bean<T> {
    public Set<Annotation> getInterceptorBindings();
    public boolean intercepts(InterceptionType type);
    public Object intercept(InterceptionType type, T instance, InvocationContext ctx) throws Exception;
}
  • getInterceptorBindings() returns the interceptor bindings of the interceptor.

  • intercepts() returns true if the interceptor intercepts the specified kind of lifecycle callback or method invocation, and false otherwise.

  • intercept() invokes the specified kind of lifecycle callback or method invocation interception upon the given instance of the interceptor.

An InterceptionType identifies the kind of lifecycle callback or business method.

public enum InterceptionType {
    AROUND_INVOKE, AROUND_CONSTRUCT, POST_CONSTRUCT, PRE_DESTROY, PRE_PASSIVATE, POST_ACTIVATE, AROUND_TIMEOUT
}

An instance of Interceptor exists for every enabled interceptor.

The ObserverMethod interface

The interface jakarta.enterprise.inject.spi.ObserverMethod defines everything the container needs to know about an observer method.

public interface ObserverMethod<T> extends Prioritized {
    public Class<?> getBeanClass();
    public Type getObservedType();
    public Set<Annotation> getObservedQualifiers();
    public Reception getReception();
    public TransactionPhase getTransactionPhase();
    public int getPriority();
    public void notify(T event);
    public void notify(EventContext<T> eventContext);
    public boolean isAsync();
}
  • getBeanClass() returns the class of the type that declares the observer method.

  • getObservedType() and getObservedQualifiers() return the observed event type and qualifiers.

  • getReception() returns IF_EXISTS for a conditional observer and ALWAYS otherwise.

  • getTransactionPhase() returns the appropriate transaction phase for a transactional observer method or IN_PROGRESS otherwise.

  • getPriority() this method inherited from Prioritized interface returns the priority that will be used by the container to determine the notification order as defined in [observer_ordering]. If this method is not implemented the default priority APPLICATION + 500 is assumed.

  • notify() calls the observer method, as defined in [observer_notification].

  • isAsync() returns true if the method is an asynchronous observer method otherwise returns false.

An instance of ObserverMethod must exist for every observer method of every enabled bean.

The Prioritized interface

CDI 2.0 introduced the prioritized interface to add programmatic priority to custom SPI implementation.

public interface Prioritized {
    int getPriority();
}

The Producer and InjectionTarget interfaces

The interface jakarta.enterprise.inject.spi.Producer provides a generic operation for producing an instance of a type.

public interface Producer<T> {
    public T produce(CreationalContext<T> ctx);
    public void dispose(T instance);
    public Set<InjectionPoint> getInjectionPoints();
}

For a Producer that represents a class:

  • produce() calls the constructor annotated @Inject if it exists, or the constructor with no parameters otherwise, as defined in [instantiation], and returns the resulting instance. If the class has interceptors, produce() is responsible for building the interceptors and decorators of the instance. The instance returned by produce() may be a proxy.

  • dispose() does nothing.

  • getInjectionPoints() returns the set of InjectionPoint objects representing all injected fields, bean constructor parameters and initializer method parameters.

For a Producer that represents a producer method or field:

  • produce() calls the producer method on, or accesses the producer field of, a contextual instance of the bean that declares the producer method, as defined in [producer_or_disposer_methods_invocation].

  • dispose() calls the disposer method, if any, on a contextual instance of the bean that declares the disposer method, as defined in [producer_or_disposer_methods_invocation], or performs any additional required cleanup, if any, to destroy state associated with a resource.

  • getInjectionPoints() returns the set of InjectionPoint objects representing all parameters of the producer method.

The subinterface jakarta.enterprise.inject.spi.InjectionTarget provides operations for performing dependency injection and lifecycle callbacks on an instance of a type.

public interface InjectionTarget<T>
        extends Producer<T> {
    public void inject(T instance, CreationalContext<T> ctx);
    public void postConstruct(T instance);
    public void preDestroy(T instance);
}
  • inject() performs dependency injection upon the given object. The container sets the value of all injected fields, and calls all initializer methods, as defined in [fields_initializer_methods].

  • postConstruct() calls the @PostConstruct callback, if it exists.

  • preDestroy() calls the @PreDestroy callback, if it exists.

Implementations of Producer and InjectionTarget must ensure that the set of injection points returned by getInjectionPoints() are injected by produce() or inject().

The BeanManager object

The interface jakarta.enterprise.inject.spi.BeanManager provides operations for obtaining contextual references for beans, along with many other operations of use to portable extensions.

The container provides a built-in bean with bean type BeanManager, scope @Dependent and qualifier @Default. The built-in implementation must be a passivation capable dependency, as defined in [passivation_capable_dependency]. Thus, any bean may obtain an instance of BeanManager by injecting it:

@Inject BeanManager manager;

Note that, an exception is thrown if the following operations are called before the AfterBeanDiscovery event is fired:

  • getBeans(String),

  • getBeans(Type, Annotation…​),

  • getPassivationCapableBean(String)

  • resolve(Set),

  • resolveDecorators(Set, Annotation…​),

  • resolveInterceptors(InterceptionType, Annotation…​),

  • resolveObserverMethods(Object, Annotation…​),

  • validate(InjectionPoint),

and if the following operations are called before the AfterDeploymentValidation event is fired:

  • createInstance(),

  • getReference(Bean, Type, CreationalContext),

  • getInjectableReference(InjectionPoint, CreationalContext).

All other operations of BeanManager may be called at any time during the execution of the application.

Obtaining a reference to the CDI container

Portable extensions and other objects sometimes interact directly with the container via programmatic API call. The abstract jakarta.enterprise.inject.spi.CDI provides access to the BeanManager as well providing lookup of bean instances.

public abstract class CDI<T> implements Instance<T> {
   public static CDI<Object> current() { ... }
   public static void setCDIProvider(CDIProvider provider);
   public abstract BeanManager getBeanManager();
}

A portable extension or other object may obtain a reference to the current container by calling CDI.current(). CDI.getBeanManager() may be called at any time after the container fires the BeforeBeanDiscovery container lifecycle event until the container fires the BeforeShutdown container lifecycle event. 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.

public interface CDIProvider extends Prioritized {
   CDI<Object> getCDI();
   default int getPriority();
}
  • getPriority() method is inherited from Prioritized interface and returns the priority for the CDIProvider. If this method is not implemented the default priority 0 is assumed.

Obtaining a contextual reference for a bean

The method BeanManager.getReference() returns a contextual reference for a given bean and bean type, as defined in [contextual_reference].

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.

Obtaining an injectable reference

The method BeanManager.getInjectableReference() returns an injectable reference for a given injection point, as defined in [injectable_reference].

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 the InjectionPoint represents a decorator delegate injection point, getInjectableReference() returns a delegate, as defined in [delegate_attribute].

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 BeanManager. When the Bean implementation performs dependency injection, it must obtain the contextual instances to inject by calling BeanManager.getInjectableReference(), passing an instance of InjectionPoint that represents the injection point and the instance of CreationalContext that was passed to Bean.create().

Obtaining non-contextual instance

A non-contextual instance can be obtained and injected from an InjectionTarget, however the InjectionTarget interface is designed to work on contextual instances. A helper class, Unmanaged provides a set of methods optimized for working with non-contextual instances.

For example:

Unmanaged<Foo> unmanagedFoo = new Unmanaged<Foo>(Foo.class);
UnmanagedInstance<Foo> fooInstance = unmanagedFoo.newInstance();
Foo foo = fooInstance.produce().inject().postConstruct().get();
... // Use the foo instance
fooInstance.preDestroy().dispose();

Obtaining a CreationalContext

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

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().

Obtaining a Bean by type

The method BeanManager.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 BeanManager was injected or the class from whose JNDI environment namespace the BeanManager was obtained, according to the rules for candidates of typesafe resolution defined in [performing_typesafe_resolution].

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.

Obtaining a Bean by name

The method BeanManager.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 BeanManager was injected or the class from whose JNDI environment namespace the BeanManager was obtained, according to the rules of name resolution defined in [name_resolution].

public Set<Bean<?>> getBeans(String name);

The parameter is a bean name.

Obtaining a passivation capable bean by identifier

The method BeanManager.getPassivationCapableBean() returns the PassivationCapable bean with the given identifier (see [passivation_capable]).

public Bean<?> getPassivationCapableBean(String id);

Resolving an ambiguous dependency

The method BeanManager.resolve() applies the ambiguous dependency resolution rules defined in [unsatisfied_and_ambig_dependencies] to a set of Bean s.

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.

BeanManager.resolve() must return null if:

  • null is passed to resolve(), or

  • no beans are passed to resolve().

Validating an injection point

The BeanManager.validate() operation validates an injection point and throws an InjectionException if there is a deployment problem (for example, an unsatisfied or unresolvable ambiguous dependency) associated with the injection point.

public void validate(InjectionPoint injectionPoint);

Firing an event

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

Event<Object> getEvent();

The returned instance can be used like a standard Event as described in [events].

Observer method resolution

The method BeanManager.resolveObserverMethods() resolves observer methods for an event according to the rules of observer resolution defined in [observer_resolution].

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.

Decorator resolution

The method BeanManager.resolveDecorators() returns the ordered list of decorators for a set of bean types and a set of qualifiers and which are enabled in the module or library containing the class into which the BeanManager was injected or the class from whose JNDI environment namespace the BeanManager was obtained, as defined in [decorator_resolution].

List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... qualifiers);

The first argument is the set of bean types of the decorated bean. The annotations are qualifiers declared by the decorated bean.

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.

If the set of bean types is empty, an IllegalArgumentException is thrown.

Interceptor resolution

The method BeanManager.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 BeanManager was injected or the class from whose JNDI environment namespace the BeanManager was obtained, as defined in [interceptor_resolution].

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.

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

A portable extension may test an annotation to determine if it is a qualifier type, scope type, stereotype or interceptor binding type, obtain the set of meta-annotations declared by a stereotype or interceptor binding type, or determine if a scope type is a normal or passivating scope.

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

public boolean isNormalScope(Class<? extends Annotation> scopeType);
public boolean isPassivatingScope(Class<? extends Annotation> scopeType);
public Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> qualifierType);
public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype);

Determining the hash code and equivalence of qualifiers and interceptor bindings

A portable extension may determine if two qualifiers or two interceptor bindings are considered equivalent for the purposes of typesafe resolution, as defined in [performing_typesafe_resolution].

public boolean areQualifiersEquivalent(Annotation qualifier1, Annotation qualifier2);
public boolean areInterceptorBindingsEquivalent(Annotation interceptorBinding1, Annotation interceptorBinding2);

A portable extension may determine the hash code of a qualifier or interceptor binding, ignoring any members annotated with @Nonbinding.

public int getQualifierHashCode(Annotation qualifier);
public int getInterceptorBindingHashCode(Annotation interceptorBinding);

Obtaining the active Context for a scope

The method BeanManager.getContext() retrieves an active context object associated with the given scope, as defined in [active_context].

public Context getContext(Class<? extends Annotation> scopeType);

Obtaining the ELResolver

The method BeanManager.getELResolver() returns the jakarta.el.ELResolver specified in [el].

public ELResolver getELResolver();

Obtaining an AnnotatedType for a class

The method BeanManager.createAnnotatedType() returns an AnnotatedType that may be used to read the annotations of the given Java class or interface.

public <T> AnnotatedType<T> createAnnotatedType(Class<T> type);

Obtaining an InjectionTarget for a class

The method BeanManager.getInjectionTargetFactory() returns a factory capable of creating container provided implementations of InjectionTarget for a given AnnotatedType or throws an IllegalArgumentException if there is a definition error associated with any injection point of the type.

public <T> InjectionTargetFactory<T> getInjectionTargetFactory(AnnotatedType<T> type);
public interface InjectionTargetFactory<T> {

    public InjectionTarget<T> createInjectionTarget(Bean<T> bean);
    public AnnotatedTypeConfigurator<T> configure();

}

Null should be passed to InjectionTargetFactory.createInjectionTarget() to create a non-contextual injection target.

  • configure() method returns an AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI to configure the AnnotatedType used to create the InjectionTargetFactory. Subsequent invocations of the configure() method within one InjectionTargetFactory instance will always return the same AnnotatedTypeConfigurator instance. Once createInjectionTarget() method has been invoked, any invocations of configure() throws an IllegalStateException.

Obtaining a Producer for a field or method

The method BeanManager.getProducerFactory() returns a factory capable of creating container provided implementations of Producer for a given AnnotatedMethod or AnnotatedField, and declaring bean, or throws an IllegalArgumentException if there is a definition error associated with the producer method or field.

public <X> ProducerFactory<X> getProducerFactory(AnnotatedField<? super X> field, Bean<X> declaringBean);
public <X> ProducerFactory<X> getProducerFactory(AnnotatedMethod<? super X> method, Bean<X> declaringBean);
public interface ProducerFactory<X> {

    public <T> Producer<T> createProducer(Bean<T> bean);

}

Null should be passed to ProducerFactory.createProducer() to create a producer of non-contextual objects.

Obtaining an InjectionPoint

The method BeanManager.createInjectionPoint() returns a container provided implementation of InjectionPoint for a given AnnotatedField or AnnotatedParameter or throws an IllegalArgumentException if there is a definition error associated with the injection point.

public InjectionPoint createInjectionPoint(AnnotatedField<?> field);
public InjectionPoint createInjectionPoint(AnnotatedParameter<?> parameter);

Obtaining a BeanAttributes

The method BeanManager.createBeanAttributes() returns a container provided implementation of BeanAttributes by reading the annotations of a given AnnotatedType or AnnotatedMember, according to the rules defined in [concepts], or throws an IllegalArgumentException if there is a definition error associated with the declared bean attributes.

public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type);
public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> member);

Obtaining a Bean

The method BeanManager.createBean() returns a container provided implementation of Bean. The methods accept:

  • a BeanAttributes, which determines the bean types, qualifiers, scope, name and stereotypes of the returned Bean, and the return values of isAlternative(), and

  • a class, which determines the return value of Bean.getClass().

  • an InjectionTargetFactory, which is used to obtain an InjectionTarget. The InjectionTarget is used to create and destroy instances of the bean, to perform dependency injection and lifecycle callbacks, and which determines the return value of Bean.getInjectionPoints().

public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<T> beanClass,
                          InjectionTargetFactory<T> injectionTargetFactory);

A second version of the method is provided to create a Bean from a producer. The method accepts:

  • a BeanAttributes, which determines the bean types, qualifiers, scope, name and stereotypes of the returned Bean, and the return values of isAlternative(), and

  • a class, which determines the return value of Bean.getClass().

  • a ProducerFactory, which is used to obtain a Producer. The Producer is used to create and destroy instances of the bean, and which determines the return value of Bean.getInjectionPoints().

public <T, X> Bean<T> createBean(BeanAttributes<T> attributes, Class<X> beanClass,
                          ProducerFactory<X> producer);

Obtaining the instance of an Extension

The method BeanManager.getExtension() returns the container’s instance of an Extension class declared in META-INF/services, or throws an IllegalArgumentException if the container has no instance of the given class.

public <T extends Extension> T getExtension(Class<T> extensionClass);

Obtain an InterceptionFactory

The method BeanManager.getInterceptionFactory() returns an InterceptionFactory for the provided type as defined in The InterceptionFactory interface.

<T> InterceptionFactory<T> createInterceptionFactory(CreationalContext<T> ctx, Class<T> clazz);

If the actual type parameter of the method is not a Java class, non-portable behavior results.

Obtain an Instance

The method BeanManager.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 BeanManager was injected or the Jakarta EE component from whose JNDI environment namespace the BeanManager was obtained, according to the rules defined in [typesafe_resolution].

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.

Alternative metadata sources

A portable extension may provide an alternative metadata source, such as configuration by XML.

The interfaces AnnotatedType, AnnotatedField, AnnotatedMethod, AnnotatedConstructor and AnnotatedParameter in the package jakarta.enterprise.inject.spi allow a portable extension to specify metadata that overrides the annotations that exist on a bean class. The portable extension is responsible for implementing the interfaces, thereby exposing the metadata to the container.

In general, the behavior is as defined by the Java Language Specification, and only deviations from the Java Language Specification are noted.

The interface jakarta.enterprise.inject.spi.AnnotatedType exposes the Class object and members.

public interface AnnotatedType<X>
        extends Annotated {
    public Class<X> getJavaClass();
    public Set<AnnotatedConstructor<X>> getConstructors();
    public Set<AnnotatedMethod<? super X>> getMethods();
    public Set<AnnotatedField<? super X>> getFields();
}
  • getConstructors() returns all default-access, public, protected or private constructors declared for the type.

  • getMethods() returns all default-access, public, protected or private methods declared on the type and those declared on any supertypes. The container should call AnnotatedMethod.getJavaMember().getDeclaringClass() to determine the type in the type hierarchy that declared the method.

  • getFields() returns all default-access, public, protected or private fields declared on the type and those declared on any supertypes. The container should call AnnotatedField.getJavaMember().getDeclaringClass() to determine the type in the type hierarchy that declared the field.

When determining annotations on a type, the container must only consider the special inheritance rules defined for scope types in [type_level_inheritance].

The interface jakarta.enterprise.inject.spi.AnnotatedField exposes the Field object.

public interface AnnotatedField<X>
        extends AnnotatedMember<X> {
    public Field getJavaMember();
}

The interface jakarta.enterprise.inject.spi.AnnotatedMethod exposes the Method object.

public interface AnnotatedMethod<X>
        extends AnnotatedCallable<X> {
    public Method getJavaMember();
}

The interface jakarta.enterprise.inject.spi.AnnotatedConstructor exposes the Constructor object.

public interface AnnotatedConstructor<X>
        extends AnnotatedCallable<X> {
    public Constructor<X> getJavaMember();
}

The interface jakarta.enterprise.inject.spi.AnnotatedParameter exposes the position of the parameter object and the declaring program element.

public interface AnnotatedParameter<X>
        extends Annotated {
    public int getPosition();
    public AnnotatedCallable<X> getDeclaringCallable();
}

The interface jakarta.enterprise.inject.spi.AnnotatedMember exposes the Member object and the AnnotatedType that defines the member.

public interface AnnotatedMember<X>
        extends Annotated {
    public Member getJavaMember();
    public boolean isStatic();
    public AnnotatedType<X> getDeclaringType();
}

The interface jakarta.enterprise.inject.spi.AnnotatedCallable exposes the parameters of an invokable object.

CDI 1.1 deprecated the method AnnotatedMember.isStatic(). The container should instead call AnnotatedMember.getJavaMember().getModifiers() to determine if the member is static.

public interface AnnotatedCallable<X>
        extends AnnotatedMember<X> {
    public List<AnnotatedParameter<X>> getParameters();
}

The interface jakarta.enterprise.inject.spi.Annotated exposes the overriding annotations and type declarations.

public interface Annotated {
    Type getBaseType();
    Set<Type> getTypeClosure();
    <T extends Annotation> T getAnnotation(Class<T> annotationType);
    <T extends Annotation> Set<T> getAnnotations(Class<T> annotationType);
    Set<Annotation> getAnnotations();
    boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
}
  • getBaseType() returns the type of the program element.

  • getTypeClosure() returns all types to which the base type should be considered assignable.

  • getAnnotation(Class<T>) returns the program element annotation of the given annotation type, or a null value.

  • getAnnotations(Class<T>) returns the program element annotations of the given annotation type, or an empty set.

  • getAnnotations() returns all annotations of the program element.

  • isAnnotationPresent(Class<T>) returns true if the program element has an annotation of the given annotation type, or false otherwise.

The container must use the operations of Annotated and its subinterfaces to discover program element types and annotations. The container must not directly call the Java Reflection API. In particular, the container must:

  • call Annotated.getBaseType() to determine the type of an injection point, event parameter or disposed parameter,

  • call Annotated.getTypeClosure() to determine the bean types of any kind of bean,

  • call Annotated.getAnnotations() to determine the scope, qualifiers, stereotypes and interceptor bindings of a bean,

  • call Annotated.isAnnotationPresent() and Annotated.getAnnotation() to read any bean annotations defined by this specification, and

  • call AnnotatedType.getConstructors(), AnnotatedType.getMethods() and AnnotatedType.getFields() to determine the members of a bean class.

AnnotatedTypeConfigurator SPI

CDI 2.0 introduced a new SPI to help defining and creating instance for type metadata.

This SPI is composed of the following interfaces:

  • jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator to configure an AnnotatedType

  • jakarta.enterprise.inject.spi.configurator.AnnotatedFieldConfigurator (defined in AnnotatedFieldConfigurator) to configure an AnnotatedField

  • jakarta.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator (defined in AnnotatedConstructorConfigurator) to configure an AnnotatedConstructor

  • jakarta.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator (defined in AnnotatedMethodConfigurator) to configure an AnnotatedMethod

  • jakarta.enterprise.inject.spi.configurator.AnnotatedParameterConfigurator (defined in AnnotatedParameterConfigurator) to configure an AnnotatedParameter

The container must provide an implementation for each of these interfaces.

AnnotatedTypeConfigurator is the entry point for this SPI. Implementation of AnnotatedTypeConfigurator is returned by methods in the following lifecycle event:

public interface AnnotatedTypeConfigurator<T> {

    AnnotatedType<T> getAnnotated();
    AnnotatedTypeConfigurator<T> add(Annotation annotation);
    AnnotatedTypeConfigurator<T> remove(Predicate<Annotation> predicate);
    AnnotatedTypeConfigurator<T> removeAll();
    Set<AnnotatedMethodConfigurator<T>> methods();
    Stream<AnnotatedMethodConfigurator<T>> filterMethods(Predicate<AnnotatedMethod<T>> predicate);
    Set<AnnotatedFieldConfigurator<T>> fields();
    Stream<AnnotatedFieldConfigurator<T>> filterFields(Predicate<AnnotatedField<T>> predicate);
    Set<AnnotatedConstructorConfigurator<T>> constructors();
    Stream<AnnotatedConstructorConfigurator<T>> filterConstructors(Predicate<AnnotatedConstructor<T>> predicate);
}
  • getAnnotated() returns the original AnnotatedType with which this configurator was initialized

  • add() adds an annotation to the configured element

  • remove() removes annotations that match the specified predicate from the configured element

  • removeAll() removes all annotations from the configured element

  • methods() returns a set of AnnotatedMethodConfigurator to configure annotations on methods

  • filterMethods() returns a Stream<AnnotatedMethodsConfigurator> filtered by applying the provided Predicate on methods()

  • fields() returns a set of AnnotatedFieldConfigurator to configure annotations on fields

  • filterFields() returns a Stream<AnnotatedFieldConfigurator> filtered by applying the provided Predicate on fields()

  • constructors() returns a set of AnnotatedConstructorConfigurator to configure annotations on constructors

  • filterConstructors() returns a Stream<AnnotatedConstructorConfigurator> filtered by applying the provided Predicate on Constructors()

AnnotatedMethodConfigurator

AnnotatedMethodConfigurator is obtained through AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI

public interface AnnotatedMethodConfigurator<T> {
    AnnotatedMethod<T> getAnnotated();
    AnnotatedMethodConfigurator<T> add(Annotation annotation);
    AnnotatedMethodConfigurator<T> remove(Predicate<Annotation> predicate);
    AnnotatedMethodConfigurator<T> removeAll();
    List<AnnotatedParameterConfigurator<T>> params();
    Stream<AnnotatedParameterConfigurator<T>> filterParams(Predicate<AnnotatedParameter<T>> predicate);
}
  • getAnnotated() returns the original AnnotatedMethod with which this configurator was initialized

  • add() adds an annotation to the configured element

  • remove() removes annotations that match the specified predicate from the configured element

  • removeAll() removes all annotations from the configured element

  • params() returns a list of AnnotatedParameterConfigurator to configure annotations on parameters.

  • filterParams(Predicate<AnnotatedParameter<T>> predicate) returns a Stream<AnnotatedParameterConfigurator> filtered by applying the provided Predicate on params()

AnnotatedConstructorConfigurator

AnnotatedConstructorConfigurator is obtained through AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI

public interface AnnotatedConstructorConfigurator<T> {
    AnnotatedConstructor<T> getAnnotated();
    AnnotatedConstructorConfigurator<T> add(Annotation annotation);
    AnnotatedConstructorConfigurator<T> remove(Predicate<Annotation> predicate);
    AnnotatedConstructorConfigurator<T> removeAll();
    List<AnnotatedParameterConfigurator<T>> params();
    Stream<AnnotatedParameterConfigurator<T>> filterParams(Predicate<AnnotatedParameter<T>> predicate);
}
  • getAnnotated() returns the original AnnotatedConstructor with which this configurator was initialized

  • add() adds an annotation to the configured element

  • remove() removes annotations that match the specified predicate from the configured element

  • removeAll() removes all annotations from the configured element

  • params() returns a list of AnnotatedParameterConfigurator to configure annotations on parameters.

  • filterParams(Predicate<AnnotatedParameter<T>> predicate) returns a Stream<AnnotatedParameterConfigurator> filtered by applying the provided Predicate on params()

AnnotatedParameterConfigurator

AnnotatedParameterConfigurator is obtained through AnnotatedMethodConfigurator (as defined in AnnotatedMethodConfigurator) and AnnotatedConstructorConfigurator as defined in AnnotatedConstructorConfigurator.

public interface AnnotatedParameterConfigurator<T> {
    AnnotatedParameter<T> getAnnotated();
    AnnotatedParameterConfigurator<T> add(Annotation annotation);
    AnnotatedParameterConfigurator<T> remove(Predicate<Annotation> predicate);
    AnnotatedParameterConfigurator<T> removeAll();
}
  • getAnnotated() returns the original AnnotatedParameter with which this configurator was initialized

  • add() adds an annotation to the configured element

  • remove() removes annotations that match the specified predicate from the configured element

  • removeAll() removes all annotations from the configured element

AnnotatedFieldConfigurator

AnnotatedFieldConfigurator is obtained through AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI:

public interface AnnotatedFieldConfigurator<T> {

    AnnotatedField<T> getAnnotated();
    AnnotatedFieldConfigurator<T> add(Annotation annotation);
    AnnotatedFieldConfigurator<T> remove(Predicate<Annotation> predicate);
    AnnotatedFieldConfigurator<T> removeAll();
}
  • getAnnotated() returns the original AnnotatedField with which this configurator was initialized

  • add() adds an annotation to the configured element

  • remove() removes annotations that match the specified predicate from the configured element

  • removeAll() removes all annotations from the configured element

Container lifecycle events

During the application initialization process, the container fires a series of events, allowing portable extensions to integrate with the container initialization process defined in [initialization]. These events are fired synchronously.

Observer methods of these events must belong to extensions. An extension is a service provider of the service jakarta.enterprise.inject.spi.Extension declared in META-INF/services.

public interface Extension {}

If any method on the event object is called outside of the observer method invocation, an IllegalStateException is thrown.

Service providers may have observer methods, which may observe any event, including any container lifecycle event, and obtain an injected BeanManager reference. Any decorators associated with BeanManager will not be applied. If other beans are injected into an extension’s observer methods, non-portable behavior results. An extension may use BeanManager.getEvent() to deliver events to observer methods defined on extensions. The container is not required to deliver events fired during application initialization to observer methods defined on beans.

The container instantiates a single instance of each extension at the beginning of the application initialization process and maintains a reference to it until the application shuts down. The container delivers event notifications to this instance by calling its observer methods.

If an extension declares a static observer method whose event parameter type:

  • is a container lifecycle event, or

  • is java.lang.Object and the event parameter has either no qualifiers or a single qualifier @Any,

non-portable behavior results.

The notification order for observer methods within extensions follows the same ordering rule as defined in [observer_ordering] for non-extension observers. The priority of an observer method may be declared using the @Priority annotation.

void beforeBeanDiscovery(@Observes @Priority(jakarta.interceptor.Interceptor.Priority.LIBRARY_BEFORE) BeforeBeanDiscovery event) { ... }

For each service provider, the container must provide a bean of scope @ApplicationScoped and qualifier @Default, supporting injection of a reference to the service provider instance. The bean types of this bean include the class of the service provider and all superclasses and interfaces.

Lifecycle events described below can be grouped in to two categories:

  • Application lifecycle events, that are fired once:

    • BeforeBeanDiscovery

    • AfterTypeDiscovery

    • AfterBeanDiscovery

    • AfterDeploymentValidation

    • BeforeShutdown

  • Bean discovery events, that are fired multiple times:

    • ProcessAnnotatedType

    • ProcessInjectionPoint

    • ProcessInjectionTarget

    • ProcessBeanAttributes

    • ProcessBean

    • ProcessProducer

    • ProcessObserverMethod

Note that the chronological order of these events is specified in [initialization].

BeforeBeanDiscovery event

The container must fire an event before it begins the type discovery process. The event object must be of type jakarta.enterprise.inject.spi.BeforeBeanDiscovery:

public interface BeforeBeanDiscovery {
    public void addQualifier(Class<? extends Annotation> qualifier);
    public void addQualifier(AnnotatedType<? extends Annotation> qualifier);
    public void addScope(Class<? extends Annotation> scopeType, boolean normal, boolean passivating);
    public void addStereotype(Class<? extends Annotation> stereotype, Annotation... stereotypeDef);
    public void addInterceptorBinding(Class<? extends Annotation> bindingType, Annotation... bindingTypeDef);
    public void addInterceptorBinding(AnnotatedType<? extends Annotation> bindingType);
    public void addAnnotatedType(AnnotatedType<?> type);
    public void addAnnotatedType(AnnotatedType<?> type, String id);
    public AnnotatedTypeConfigurator<?> addAnnotatedType(Class<T> type,String id);
    <T extends Annotation> AnnotatedTypeConfigurator<T> configureQualifier(Class<T> qualifier);
    <T extends Annotation> AnnotatedTypeConfigurator<T> configureInterceptorBinding(Class<T> bindingType);
}
  • addQualifier() declares an annotation type as a qualifier type.

  • addScope() declares an annotation type as a scope type.

  • addStereotype() declares an annotation type as a stereotype, and specifies its meta-annotations.

  • addInterceptorBinding() declares an annotation type as an interceptor binding type, and specifies its meta-annotations.

  • addAnnotatedType() adds a given AnnotatedType to the set of types which will be scanned during bean discovery, with an optional identifier. The first version of the method is deprecated since version 1.1 of Contexts and Dependency Injection.

    The third version of the method, returns a new AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI to easily configure the AnnotatedType which will be added at the end of the observer invocation. The returned AnnotatedTypeConfigurator is initialized with type and annotations of the provided class.

  • configureQualifier() returns a new AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI to configure a new AnnotatedType and declares it as a qualifier type.

  • configureInterceptorBinding() returns a new AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI to configure a new AnnotatedType and declares it as an interceptor binding.

void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event) { ... }

If any observer method of the BeforeBeanDiscovery event throws an exception, the exception is treated as a definition error by the container.

If any BeforeBeanDiscovery method is called outside of the observer method invocation, an IllegalStateException is thrown.

AfterTypeDiscovery event

The container must fire an event when it has fully completed the type discovery process and before it begins the bean discovery process. The event object must be of type jakarta.enterprise.inject.spi.AfterTypeDiscovery.

public interface AfterTypeDiscovery {
    public List<Class<?>> getAlternatives();
    public List<Class<?>> getInterceptors();
    public List<Class<?>> getDecorators();
    public void addAnnotatedType(AnnotatedType<?> type, String id);
    public AnnotatedTypeConfigurator<?> addAnnotatedType(Class<T> type,String id);
}
  • getAlternatives() returns the ordered list of enabled alternatives for the application, sorted by priority in ascending order. Alternatives enabled for a bean archive are not included in the list.

  • getInterceptors() returns the ordered list of enabled interceptors for the application, sorted by priority in ascending order. Interceptors enabled for a bean archive are not included in the list.

  • getDecorators() returns the ordered list of enabled decorators for the application, sorted by priority in ascending order. Decorators enabled for a bean archive are not included in the list.

  • addAnnotatedType() adds a given AnnotatedType to the set of types which will be scanned during bean discovery, with an identifier.

    The second version of the method, returns a new AnnotatedTypeConfigurator as defined in AnnotatedTypeConfigurator SPI to easily configure the AnnotatedType which will be added at the end of observer invocation. The returned AnnotatedTypeConfigurator is initialized with type and annotations of the provided class.

If an alternative, interceptor or decorator is added using AfterTypeDiscovery.addAnnotatedType(), non-portable behavior results.

Any observer of this event is permitted to add classes to, or remove classes from, the list of alternatives, list of interceptors or list of decorators. The container must use the final values of these collections, after all observers of AfterTypeDiscovery have been called, to determine the order of the enabled alternatives, interceptors, and decorators for application. The initial values of these collections are defined by the @Priority annotation.

void afterTypeDiscovery(@Observes AfterTypeDiscovery event) { ... }

If any observer method of a AfterTypeDiscovery event throws an exception, the exception is treated as a definition error by the container.

If any AfterTypeDiscovery method is called outside of the observer method invocation, an IllegalStateException is thrown.

AfterBeanDiscovery event

The container must fire an event when it has fully completed the bean discovery process, validated that there are no definition errors relating to the discovered beans, and registered Bean and ObserverMethod objects for the discovered beans.

The event object must be of type jakarta.enterprise.inject.spi.AfterBeanDiscovery:

public interface AfterBeanDiscovery {
    public void addDefinitionError(Throwable t);
    public void addBean(Bean<?> bean);
    public BeanConfigurator<?> addBean();
    public void addObserverMethod(ObserverMethod<?> observerMethod);
    public ObserverMethodConfigurator<?> addObserverMethod();
    public void addContext(Context context);
    public <T> AnnotatedType<T> getAnnotatedType(Class<T> type, String id);
    public <T> Iterable<AnnotatedType<T>> getAnnotatedTypes(Class<T> type);
}
  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after all observers have been notified.

  • addBean() fires an event of type ProcessSyntheticBean containing the given Bean and then registers the Bean with the container, thereby making it available for injection into other beans. The given Bean may implement Interceptor or Decorator.

    The second version of the method, returns a new BeanConfigurator as defined in BeanConfigurator interface to easily configure the Bean which will be added at the end of observer invocation. If the container is unable to process the configurator it automatically detects the problem and treats it as a deployment problem.

  • addObserverMethod() fires an event of type ProcessSyntheticObserverMethod containing the given ObserverMethod and then registers the ObserverMethod with the container, thereby making it available for event notifications.

    If the given ObserverMethod does not override either ObserverMethod.notify(T) or ObserverMethod.notify(EventContext<T>), the container automatically detects the problem and treats it as a definition error.

    The second version of the method, returns a new ObserverMethodConfigurator as defined in ObserverMethodConfigurator interface to easily configure the ObserverMethod which will be added at the end of observer invocation. If the container is unable to process the configurator it automatically detects the problem and treats it as a deployment problem.

  • addContext() registers a custom Context object with the container.

  • getAnnotatedType() and getAnnotatedTypes() returns the AnnotatedType s discovered or added during container initialization. The id of an AnnotatedType added by the container is not defined. If the id passed is null, the container should substitute the container generated id.

A portable extension may take advantage of this event to register beans, interceptors, decorators, observer methods and custom context objects with the container.

void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) { ... }

If any observer method of the AfterBeanDiscovery event throws an exception, the exception is treated as a definition error by the container.

If any AfterBeanDiscovery method is called outside of the observer method invocation, an IllegalStateException is thrown.

BeanConfigurator interface

CDI 2.0 introduced the jakarta.enterprise.inject.spi.configurator.BeanConfigurator interface to help configuring a new Bean instance.

With BeanConfigurator you can perform all the operations defined in BeanAttributesConfigurator interface plus the following:

  • Initialize the bean metadata with one of its read() methods. It can be done from an existing BeanAttributes or by reading metadata on a given AnnotatedType, according to the rules defined in [concepts].

  • Set the class of the bean with beanClass method.

  • Add an injection point for the bean with addInjectionPoint method.

  • Add multiple injection points for the bean with addInjectionPoints methods.

  • Replace all injection points for the bean with injectionPoints methods.

  • Make the bean implements PassivationCapable and set its id with id method.

  • Set a callback to create a bean instance with createWith() or produceWith() method.

  • Set a callback to destroy a bean instance with destroyWith() or disposeWith() method.

If a BeanConfigurator has no scope specified, the default scope rules, defined in [default_scope], apply.

ObserverMethodConfigurator interface

CDI 2.0 introduced the jakarta.enterprise.inject.spi.configurator.ObserverMethodConfigurator interface to help configuring an ObserverMethod instance.

With ObserverMethodConfigurator you can perform the following operations:

  • Read the observer metadata from a java.lang.reflect.Method, AnnotatedMethod or an existing ObserverMethod with one of its read() methods.

  • Set the ObserverMethod bean class with beanClass method.

  • Set the type of the observed event with observedType method.

  • Add a qualifier with addQualifier method.

  • Set or add multiple qualifiers with addQualifiers and qualifiers methods.

  • Set the Reception type with reception method.

  • Set the TransactionPhase type with transactionPhase method.

  • Set the priority with priority method.

  • Define the EventConsumer to call on notification with notifyWith method.

  • Make the observer asynchronous with async method.

AfterDeploymentValidation event

The container must fire an event after it has validated that there are no deployment problems and before creating contexts or processing requests.

The event object must be of type jakarta.enterprise.inject.spi.AfterDeploymentValidation:

public interface AfterDeploymentValidation {
    public void addDeploymentProblem(Throwable t);
}
  • addDeploymentProblem() registers a deployment problem with the container, causing the container to abort deployment after all observers have been notified.

void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) { ... }

If any observer method of the AfterDeploymentValidation event throws an exception, the exception is treated as a deployment problem by the container.

If any AfterDeploymentValidation method is called outside of the observer method invocation, an IllegalStateException is thrown.

The container must not allow any request to be processed by the deployment until all observers of this event return.

BeforeShutdown event

The container must fire a final event after it has finished processing requests and destroyed all contexts.

The event object must be of type jakarta.enterprise.inject.spi.BeforeShutdown:

public interface BeforeShutdown {}
void beforeShutdown(@Observes BeforeShutdown event, BeanManager manager) { ... }

If any observer method of the BeforeShutdown event throws an exception, the exception is ignored by the container.

ProcessAnnotatedType event

The container must fire an event, before it processes a type, for every Java class, interface (excluding annotation type, a special kind of interface type) or enum discovered as defined in [type_discovery_steps].

An event is not fired for any type annotated with @Vetoed, or in a package annotated with @Vetoed.

The event object must be of type jakarta.enterprise.inject.spi.ProcessAnnotatedType<X>, where X is the class, for types discovered in a bean archive, or of type jakarta.enterprise.inject.spi.ProcessSyntheticAnnotatedType<X> for types added by BeforeBeanDiscovery.addAnnotatedType() or AfterTypeDiscovery.addAnnotatedType().

The annotation @WithAnnotations may be applied to the event parameter. If the annotation is applied, the container must only deliver ProcessAnnotatedType events for types which contain at least one of the annotations specified. The annotation can appear on the annotated type, or on any member, or any parameter of any member of the annotated type, as defined in Alternative metadata sources. The annotation may be applied as a meta-annotation on any annotation considered.

If the @WithAnnotations annotation is applied to any other event parameter, the container automatically detects the problem and treats it as a definition error.

public interface ProcessAnnotatedType<X> {
    public AnnotatedType<X> getAnnotatedType();
    public void setAnnotatedType(AnnotatedType<X> type);
    public AnnotatedTypeConfigurator<X> configureAnnotatedType();
    public void veto();
}
interface ProcessSyntheticAnnotatedType<X> extends ProcessAnnotatedType<X> {
    public Extension getSource();
}
  • getAnnotatedType() returns the AnnotatedType object that will be used by the container to read the declared annotations.

  • setAnnotatedType() replaces the AnnotatedType.

  • configureAnnotatedType() returns an AnnotatedTypeConfigurator (as defined in AnnotatedTypeConfigurator SPI) initialized with the AnnotatedType processed by the event to easily configure the AnnotatedType which will be used to replace the original one at the end of observer invocation. The method always returns the same AnnotatedTypeConfigurator

  • veto() forces the container to ignore the type.

  • getSource() returns the Extension instance that added the annotated type.

Any observer of this event is permitted to wrap and/or replace the AnnotatedType by calling either setAnnotatedType() or configureAnnotatedType(). If both methods are called within an observer notification an IllegalStateException is thrown. The container must use the final value of this property, after all observers have been called, as the only source of types and annotations for the program elements.

For example, the following observer decorates the AnnotatedType for every class that is discovered by the container.

<T> void decorateAnnotatedType(@Observes ProcessAnnotatedType<T> pat) {
    pat.setAnnotatedType( decorate( pat.getAnnotatedType() ) );
}

If any observer method of a ProcessAnnotatedType event throws an exception, the exception is treated as a definition error by the container.

If any ProcessAnnotatedType method is called outside of the observer method invocation, an IllegalStateException is thrown.

ProcessInjectionPoint event

The container must fire an event for every injection point of every bean, interceptor or decorator.

The event object must be of type jakarta.enterprise.inject.spi.ProcessInjectionPoint<T, X> where T is the bean class, and X is the declared type of the injection point.

public interface ProcessInjectionPoint<T, X> {
    public InjectionPoint getInjectionPoint();
    public void setInjectionPoint(InjectionPoint injectionPoint);
    public InjectionPointConfigurator configureInjectionPoint();
    public void addDefinitionError(Throwable t);
}
  • getInjectionPoint() returns the InjectionPoint object that will be used by the container to perform injection.

  • setInjectionPoint() replaces the InjectionPoint.

  • configureInjectionPoint() returns an InjectionPointConfigurator (as defined in InjectionPointConfigurator interface) initialized with the InjectionPoint processed by the event to easily configure the InjectionPoint which will be used to replace the original one at the end of observer invocation. The method always returns the same InjectionPointConfigurator.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

Any observer of this event is permitted to wrap and/or replace the InjectionPoint by calling either setInjectionPoint() or configureInjectionPoint(). If both methods are called within an observer notification an IllegalStateException is thrown. The container must use the final value of this property, after all observers have been called, whenever it performs injection upon the injection point.

If any observer method of a ProcessInjectionPoint event throws an exception, the exception is treated as a definition error by the container.

If any ProcessInjectionPoint method is called outside of the observer method invocation, an IllegalStateException is thrown.

InjectionPointConfigurator interface

CDI 2.0 introduced the jakarta.enterprise.inject.spi.configurator.InjectionPointConfigurator interface to help configure an existing InjectionPoint instance.

With InjectionPointConfigurator you can perform the following operations:

  • Set the type of InjectionPoint with type method.

  • Add a qualifier with addQualifier method.

  • Set or add multiple qualifiers with addQualifiers and qualifiers methods.

  • Make the injection point delegate with delegate method.

  • Make the injection point a transient field with transientField method.

ProcessInjectionTarget event

The container must fire an event for every bean, interceptor or decorator.

The event object must be of type jakarta.enterprise.inject.spi.ProcessInjectionTarget<X>, where X is the bean class.

public interface ProcessInjectionTarget<X> {
    public AnnotatedType<X> getAnnotatedType();
    public InjectionTarget<X> getInjectionTarget();
    public void setInjectionTarget(InjectionTarget<X> injectionTarget);
    public void addDefinitionError(Throwable t);
}
  • getAnnotatedType() returns the AnnotatedType representing the bean class.

  • getInjectionTarget() returns the InjectionTarget object that will be used by the container to perform injection.

  • setInjectionTarget() replaces the InjectionTarget.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

Any observer of this event is permitted to wrap and/or replace the InjectionTarget. The container must use the final value of this property, after all observers have been called, whenever it performs injection upon the managed bean.

If any observer method of a ProcessInjectionTarget event throws an exception, the exception is treated as a definition error by the container.

If any ProcessInjectionTarget method is called outside of the observer method invocation, an IllegalStateException is thrown.

ProcessBeanAttributes event

The container must fire an event for each managed bean, producer, interceptor or decorator deployed in a bean archive, before registering the Bean object. No event is fired for any:

  • @New qualified bean, defined in [new], or,

  • beans added programmatically using AfterBeanDiscovery.addBean(), or,

  • for any built-in beans.

The event object must be of type jakarta.enterprise.inject.spi.ProcessBeanAttributes<T> where T is the bean class of the bean, the return type of the producer method, or the type of the producer field.

Resources are considered to be producer fields.

public interface ProcessBeanAttributes<T> {
    public Annotated getAnnotated();
    public BeanAttributes<T> getBeanAttributes();
    public void setBeanAttributes(BeanAttributes<T> beanAttributes);
    public BeanAttributesConfigurator<T> configureBeanAttributes();
    public void addDefinitionError(Throwable t);
    public void veto();
    public void ignoreFinalMethods();
}
  • getAnnotated() returns the AnnotatedType representing the bean class, the AnnotatedMethod representing the producer field, or the AnnotatedField representing the producer field.

  • getBeanAttributes() returns the BeanAttributes object that will be used by the container to manage instances of the bean.

  • setBeanAttributes() replaces the BeanAttributes.

  • configureBeanAttributes() returns a BeanAttributesConfigurator (as defined in BeanAttributesConfigurator interface) initialized with the BeanAttributes processed by the event to easily configure the BeanAttributes which will be used to replace the original one at the end of observer invocation. The method always returns the same BeanAttributesConfigurator.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

  • veto() forces the container to ignore the bean.

  • ignoreFinalMethods() Instructs the container to ignore all non-static, final methods with public, protected or default visibility declared on any bean type of the specific bean during validation of injection points that require proxyable bean type. These method should never be invoked upon bean instances. Otherwise, unpredictable behavior results. It will bypass standard rules defined in [unproxyable].

Any observer of this event is permitted to wrap and/or replace the BeanAttributes by calling either setBeanAttributes() or configureBeanAttributes(). If both methods are called within an observer notification an IllegalStateException is thrown. The container must use the final value of this property, after all observers have been called, to manage instances of the bean. Changes to BeanAttributes are not propagated to the annotated type from which the bean definition was created.

Any bean which has its bean attributes altered must have it’s definition validated during deployment validation.

If any observer method of a ProcessBeanAttributes event throws an exception, the exception is treated as a definition error by the container.

If any ProcessBeanAttributes method is called outside of the observer method invocation, an IllegalStateException is thrown.

BeanAttributesConfigurator interface

CDI 2.0 introduced the jakarta.enterprise.inject.spi.configurator.BeanAttributesConfigurator interface to help configuring a new BeanAttributes instance.

BeanAttributesConfigurator is obtainable during ProcessBeanAttributes event and is therefore automatically initialized from existing BeanAttributes.

With BeanAttributesConfigurator you can perform the following operations :

  • Add type with addType or addTransitiveTypeClosure methods.

  • Set multiple types with types methods.

  • Set scope with scope method.

  • Add a qualifier with addQualifier method.

  • Set or add multiple qualifiers with addQualifiers and qualifiers methods.

  • Add a stereotype with addStereotype method.

  • Set or add multiple stereotypes with addStereotypes and stereotypes methods.

  • Set the bean name name method.

  • Make the bean an alternative with alternative methods.

ProcessBean event

The container must fire an event for each bean, interceptor or decorator deployed in a bean archive, after firing the ProcessBeanAttributes for the bean and before registering the Bean object. No event is fired for any @New qualified bean, defined in [new].

The event object type in the package jakarta.enterprise.inject.spi depends upon what kind of bean was discovered:

  • For a managed bean with bean class X, the container must raise an event of type ProcessManagedBean<X>.

  • For a producer method with method return type T of a bean with bean class X, the container must raise an event of type ProcessProducerMethod<T, X>.

  • For a producer field with field type T of a bean with bean class X, the container must raise an event of type ProcessProducerField<T, X>.

  • For a custom implementation of Bean, the container must raise an event of type ProcessSyntheticBean<X>.

The interface jakarta.enterprise.inject.spi.ProcessBean is a supertype of all these event types:

public interface ProcessBean<X> {
    public Annotated getAnnotated();
    public Bean<X> getBean();
    public void addDefinitionError(Throwable t);
}
  • getAnnotated() returns the AnnotatedType representing the bean class, the AnnotatedMethod representing the producer method, or the AnnotatedField representing the producer field. If invoked upon a ProcessSyntheticBean event, non-portable behavior results and the returned value should be ignored.

  • getBean() returns the Bean object that is about to be registered. The Bean may implement Interceptor or Decorator.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

public interface ProcessManagedBean<X>
        extends ProcessBean<X> {
    public AnnotatedType<X> getAnnotatedBeanClass();
}
public interface ProcessProducerMethod<T, X>
        extends ProcessBean<X> {
    public AnnotatedMethod<T> getAnnotatedProducerMethod();
    public AnnotatedParameter<T> getAnnotatedDisposedParameter();
}
public interface ProcessProducerField<T, X>
        extends ProcessBean<X> {
    public AnnotatedField<T> getAnnotatedProducerField();
    public AnnotatedParameter<T> getAnnotatedDisposedParameter();
}
public interface ProcessSyntheticBean<X>
        extends ProcessBean<X> {
    public Extension getSource();
}

If any observer method of a ProcessBean event throws an exception, the exception is treated as a definition error by the container.

If any ProcessBean method is called outside of the observer method invocation, an IllegalStateException is thrown.

ProcessProducer event

The container must fire an event for each producer method or field of each bean, including resources.

The event object must be of type jakarta.enterprise.inject.spi.ProcessProducer<T, X>, where T is the bean class of the bean that declares the producer method or field and X is the return type of the producer method or the type of the producer field.

public interface ProcessProducer<T, X> {
    public AnnotatedMember<T> getAnnotatedMember();
    public Producer<X> getProducer();
    public void setProducer(Producer<X> producer);
    public ProducerConfigurator<X> configureProducer();
    public void addDefinitionError(Throwable t);
}
  • getAnnotatedMember() returns the AnnotatedField representing the producer field or the AnnotatedMethod representing the producer method.

  • getProducer() returns the Producer object that will be used by the container to call the producer method or read the producer field.

  • setProducer() replaces the Producer.

  • configureProducer() returns a ProducerConfigurator (as defined in ProducerConfigurator interface) initialized with the Producer processed by this event to configure the Producer that will replace the original one at the end of the observer invocation. Each call returns the same configurator instance within an observer notification.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

Any observer of this event is permitted to wrap and/or replace the Producer by calling either setProducer() or configureProducer(). If both methods are called within an observer notification an IllegalStateException is thrown. The container must use the final value of this property, after all observers have been called, whenever it calls the producer or disposer.

For example, this observer decorates the Producer for all producer methods and fields of type EntityManager.

void decorateEntityManager(@Observes ProcessProducer<?, EntityManager> pp) {
    pit.setProducer( decorate( pp.getProducer() ) );
}

If any observer method of a ProcessProducer event throws an exception, the exception is treated as a definition error by the container.

If any ProcessProducer method is called outside of the observer method invocation, an IllegalStateException is thrown.

ProducerConfigurator interface

CDI 2.0 introduced the jakarta.enterprise.inject.spi.configurator.ProducerConfigurator interface to help configuring a Producer instance.

With ProducerConfigurator you can perform the following operations:

  • Set a callback to produce a new instance with produceWith() method.

  • Set a callback to destroy the produced instance with disposeWith() method.

ProcessObserverMethod event

The container must fire an event for each observer method of each enabled bean, before registering the ObserverMethod object.

The event object must be of type jakarta.enterprise.inject.spi.ProcessObserverMethod<T, X>, where T is the observed event type of the observer method and X is the bean class of the bean that declares the observer method.

For a custom implementation of jakarta.enterprise.inject.spi.ObserverMethod, the container must raise an event of type jakarta.enterprise.inject.spi.ProcessSyntheticObserverMethod<T, X>, where T is the observed event type of the observer method and X is the return value of ObserverMethod.getBeanClass().

public interface ProcessObserverMethod<T, X> {
    public AnnotatedMethod<X> getAnnotatedMethod();
    public ObserverMethod<T> getObserverMethod();
    public void addDefinitionError(Throwable t);
    public void setObserverMethod(ObserverMethod<T> observerMethod);
    public ObserverMethodConfigurator<T> setObserverMethod();
    public void veto();
}
public interface ProcessSyntheticObserverMethod<T, X> extends ProcessObserverMethod<T, X> {
    public Extension getSource();
}
  • getAnnotatedMethod() returns the AnnotatedMethod representing the observer method. If invoked upon a ProcessSyntheticObserverMethod event, non-portable behavior results and the returned value should be ignored.

  • getObserverMethod() returns the ObserverMethod object that will be used by the container to call the observer method.

  • addDefinitionError() registers a definition error with the container, causing the container to abort deployment after bean discovery is complete.

  • setObserverMethod() replaces the ObserverMethod.

  • configureObserverMethod() returns an ObserverMethodConfigurator (as defined in ObserverMethodConfigurator interface) initialized with the ObserverMethod processed by the event to easily configure the ObserverMethod which will be used to replace the original one at the end of observer invocation. The method always returns the same ObserverMethodConfigurator.

  • veto() forces the container to ignore the ObserverMethod.

  • getSource() returns the Extension instance that added the observer method.

Any observer of this event is permitted to wrap and/or replace the ObserverMethod by calling either setObserverMethod() or configureObserverMethod(). If both methods are called within an observer notification an IllegalStateException is thrown. The container must use the final value of this property, after all observers have been called, whenever it performs observer resolution.

If any observer method of a ProcessObserverMethod event throws an exception, the exception is treated as a definition error by the container.

If any ProcessObserverMethod method is called outside of the observer method invocation, an IllegalStateException is thrown.

Configurators interfaces

CDI 2.0 introduced the following Configurators interface:

The container must provide implementation for all these configurators and make them available in matching container lifecycle events as defined in Container lifecycle events.

The InterceptionFactory interface

CDI 2.0 introduces the jakarta.enterprise.inject.spi.InterceptionFactory<T> interface, which allows to create a wrapper instance whose method invocations are intercepted by method interceptors and forwarded to a provided instance.

public interface InterceptionFactory<T> {
    InterceptionFactory<T> ignoreFinalMethods();
    AnnotatedTypeConfigurator<T> configure();
    T createInterceptedInstance(T instance);
}
  • ignoreFinalMethods() instructs the container to ignore all non-static, final methods with public, protected or default visibility declared by any class in the type hierarchy of the intercepted instance during invocation of createInterceptedInstance() method. Ignored methods should never be invoked upon the wrapper instance. Otherwise, unpredictable behavior results.

  • configure() returns an AnnotatedTypeConfigurator (as defined in AnnotatedTypeConfigurator SPI) initialized with the AnnotatedType created either for the class passed to BeanManager.createInterceptionFactory(CreationalContext, Class) or derived from the InterceptionFactory parameter injection point. The method always return the same AnnotatedTypeConfigurator

  • createInterceptedInstance() returns a wrapper instance whose method invocations are intercepted by method interceptors and forwarded to a provided instance. The method can be only called once, subsequent calls will throw an IllegalStateException. If the type of the instance is not proxyable as defined in [unproxyable] an UnproxyableResolutionException exception is thrown. This rule can be loosen by calling ignoreFinalMethods() before this method. If the provided instance is an internal container construct (such as client proxy), non-portable behavior results.

An InterceptionFactory can be obtained be calling BeanManager.createInterceptionFactory() as defined in Obtain an InterceptionFactory.

The container must provide a built-in bean with scope @Dependent, bean type InterceptionFactory and qualifier @Default.

If an injection point of type InterceptionFactory and qualifier @Default exists and is not a parameter of a producer method, the container automatically detects the problem and treats it as a definition error.

If an injection point of type InterceptionFactory has a type parameter that is not a Java class, non-portable behavior results.

The following example demonstrates a producer method definition using InterceptionFactory. The produced bean instance will be a wrapper of Product with single interceptor associated by ActionBinding:

@Produces
@RequestScoped
public Product createInterceptedProduct(InterceptionFactory<Product> interceptionFactory) {
  interceptionFactory.configure().add(ActionBinding.Literal.INSTANCE);
  return interceptionFactory.createInterceptedInstance(new Product());
}