Jakarta Contexts and Dependency Injection: Advanced Topics
We are working on a fresh, updated Jakarta EE Tutorial. This section hasn’t yet been updated. |
This chapter describes more advanced features of Jakarta Contexts and Dependency Injection. Specifically, it covers additional features CDI provides to enable loose coupling of components with strong typing, in addition to those described in Overview of CDI.
Packaging CDI Applications
When you deploy a Jakarta EE application, CDI looks for beans inside bean archives. A bean archive is any module that contains beans that the CDI runtime can manage and inject. There are two kinds of bean archives: explicit bean archives and implicit bean archives.
An explicit bean archive is an archive that contains a beans.xml
deployment descriptor, which can be an empty file, contain no version number, or contain the version number 3.0 with the bean-discovery-mode
attribute set to all
.
For example:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0" bean-discovery-mode="all">
...
</beans>
CDI can manage and inject any bean in an explicit archive, except those annotated with @Vetoed
.
An implicit bean archive is an archive that contains some beans annotated with a scope type, contains no beans.xml
deployment descriptor, or contains a beans.xml
deployment descriptor with the bean-discovery-mode
attribute set to annotated
.
In an implicit archive, CDI can only manage and inject beans annotated with a scope type.
For a web application, the beans.xml
deployment descriptor, if present, must be in the WEB-INF
directory.
For enterprise bean modules or JAR files, the beans.xml
deployment descriptor, if present, must be in the META-INF
directory.
Using Alternatives in CDI Applications
When you have more than one version of a bean that you use for different purposes, you can choose between them during the development phase by injecting one qualifier or another, as shown in The simplegreeting CDI Example.
Instead of having to change the source code of your application, however, you can make the choice at deployment time by using alternatives.
Alternatives are commonly used for purposes such as the following:
-
To handle client-specific business logic that is determined at runtime
-
To specify beans that are valid for a particular deployment scenario (for example, when country-specific sales tax laws require country-specific sales tax business logic)
-
To create dummy (mock) versions of beans to be used for testing
To make a bean available for lookup, injection, or EL resolution using this mechanism, give it a jakarta.enterprise.inject.Alternative
annotation and then use the alternatives
element to specify it in the beans.xml
file.
For example, you might want to create a full version of a bean and also a simpler version that you use only for certain kinds of testing.
The example described in The encoder Example: Using Alternatives contains two such beans, CoderImpl
and TestCoderImpl
.
The test bean is annotated as follows:
@Alternative
public class TestCoderImpl implements Coder { ... }
The full version is not annotated:
public class CoderImpl implements Coder { ... }
The managed bean injects an instance of the Coder
interface:
@Inject
Coder coder;
The alternative version of the bean is used by the application only if that version is declared as follows in the beans.xml
file:
<beans ...>
<alternatives>
<class>ee.jakarta.tutorial.encoder.TestCoderImpl</class>
</alternatives>
</beans>
If the alternatives
element is commented out in the beans.xml
file, the CoderImpl
class is used.
You can also have several beans that implement the same interface, all annotated @Alternative
.
In this case, you must specify in the beans.xml
file which of these alternative beans you want to use.
If CoderImpl
were also annotated @Alternative
, one of the two beans would always have to be specified in the beans.xml
file.
The alternatives that you specify in the beans.xml
file apply only to classes in the same archive.
Use the @Priority
annotation to specify alternatives globally for an application that consists of multiple modules, as in the following example:
@Alternative
@Priority(Interceptor.Priority.APPLICATION+10)
public class TestCoderImpl implements Coder { ... }
The alternative with higher priority value is selected if several alternative beans that implement the same interface are annotated with @Priority
.
You do not need to specify the alternative in the beans.xml
file when you use the @Priority
annotation.
Using Specialization
Specialization has a function similar to that of alternatives in that it allows you to substitute one bean for another. However, you might want to make one bean override the other in all cases. Suppose you defined the following two beans:
@Default @Asynchronous
public class AsynchronousService implements Service { ... }
@Alternative
public class MockAsynchronousService extends AsynchronousService { ... }
If you then declared MockAsynchronousService
as an alternative in your beans.xml
file, the following injection point would resolve to MockAsynchronousService
:
@Inject Service service;
The following, however, would resolve to AsynchronousService
rather than MockAsynchronousService
, because MockAsynchronousService
does not have the @Asynchronous
qualifier:
@Inject @Asynchronous Service service;
To make sure that MockAsynchronousService
was always injected, you would have to implement all bean types and bean qualifiers of AsynchronousService
.
However, if AsynchronousService
declared a producer method or observer method, even this cumbersome mechanism would not ensure that the other bean was never invoked.
Specialization provides a simpler mechanism.
Specialization happens at development time as well as at runtime. If you declare that one bean specializes another, it extends the other bean class, and at runtime the specialized bean completely replaces the other bean. If the first bean is produced by means of a producer method, you must also override the producer method.
You specialize a bean by giving it the jakarta.enterprise.inject.Specializes
annotation.
For example, you might declare a bean as follows:
@Specializes
public class MockAsynchronousService extends AsynchronousService { ... }
In this case, the MockAsynchronousService
class will always be invoked instead of the AsynchronousService
class.
Usually, a bean marked with the @Specializes
annotation is also an alternative and is declared as an alternative in the beans.xml
file.
Such a bean is meant to stand in as a replacement for the default implementation, and the alternative implementation automatically inherits all qualifiers of the default implementation as well as its EL name, if it has one.
Using Producer Methods, Producer Fields, and Disposer Methods in CDI Applications
A producer method generates an object that can then be injected.Typically, you use producer methods in the following situations:
-
When you want to inject an object that is not itself a bean
-
When the concrete type of the object to be injected may vary at runtime
-
When the object requires some custom initialization that the bean constructor does not perform
For more information on producer methods, see Injecting Objects by Using Producer Methods.
A producer field is a simpler alternative to a producer method; it is a field of a bean that generates an object. It can be used instead of a simple getter method. Producer fields are particularly useful for declaring Jakarta EE resources such as data sources, JMS resources, and web service references.
A producer method or field is annotated with the jakarta.enterprise.inject.Produces
annotation.
Using Producer Methods
A producer method can allow you to select a bean implementation at runtime instead of at development time or deployment time. For example, in the example described in The producermethods Example: Using a Producer Method to Choose a Bean Implementation, the managed bean defines the following producer method:
@Produces
@Chosen
@RequestScoped
public Coder getCoder() {
switch (coderType) {
case TEST:
return new TestCoderImpl();
case SHIFT:
return new CoderImpl();
default:
return null;
}
}
Here, getCoder
becomes in effect a getter method, and when the coder
property is injected with the same qualifier and other annotations as the method, the selected version of the interface is used.
@Inject
@Chosen
@RequestScoped
Coder coder;
Specifying the qualifier is essential: It tells CDI which Coder
to inject.
Without it, the CDI implementation would not be able to choose between CoderImpl
, TestCoderImpl
, and the one returned by getCoder
and would cancel deployment, informing the user of the ambiguous dependency.
Using Producer Fields to Generate Resources
A common use of a producer field is to generate an object such as a JDBC DataSource
or a Jakarta Persistence EntityManager
(see Introduction to Jakarta Persistence, for more information).
The object can then be managed by the container.
For example, you could create a @UserDatabase
qualifier and then declare a producer field for an entity manager as follows:
@Produces
@UserDatabase
@PersistenceContext
private EntityManager em;
The @UserDatabase
qualifier can be used when you inject the object into another bean, RequestBean
, elsewhere in the application:
@Inject
@UserDatabase
EntityManager em;
...
The producerfields Example: Using Producer Fields to Generate Resources shows how to use producer fields to generate an entity manager.
You can use a similar mechanism to inject @Resource
, @EJB
, or @WebServiceRef
objects.
To minimize the reliance on resource injection, specify the producer field for the resource in one place in the application, and then inject the object wherever in the application you need it.
Using a Disposer Method
You can use a producer method or a producer field to generate an object that needs to be removed when its work is completed.
If you do, you need a corresponding disposer method, annotated with a @Disposes
annotation.
For example, you can close the entity manager as follows:
public void close(@Disposes @UserDatabase EntityManager em) {
em.close();
}
The disposer method is called automatically when the context ends (in this case, at the end of the conversation, because RequestBean
has conversation scope), and the parameter in the close
method receives the object produced by the producer field.
Using Predefined Beans in CDI Applications
Jakarta EE provides predefined beans that implement the following interfaces.
-
jakarta.transaction.UserTransaction
: A Jakarta Transactions user transaction. -
java.security.Principal
: The abstract notion of a principal, which represents any entity, such as an individual, a corporation, or a login ID. Whenever the injected principal is accessed, it always represents the identity of the current caller. For example, a principal is injected into a field at initialization. Later, a method that uses the injected principal is called on the object into which the principal was injected. In this situation, the injected principal represents the identity of the current caller when the method is run. -
jakarta.validation.Validator
: A validator for bean instances. The bean that implements this interface enables aValidator
object for the default bean validation objectValidatorFactory
to be injected. -
jakarta.validation.ValidatorFactory
: A factory class for returning initializedValidator
instances. The bean that implements this interface enables the default bean validationValidatorFactory
object to be injected. -
jakarta.servlet.http.HttpServletRequest
: An HTTP request from a client. The bean that implements this interface enables a servlet to obtain all the details of a request. -
jakarta.servlet.http.HttpSession
: An HTTP session between a client and a server. The bean that implements this interface enables a servlet to access information about a session and to bind objects to a session. -
jakarta.servlet.ServletContext
: A context object that servlets can use to communicate with the servlet container.
To inject a predefined bean, create an injection point to obtain an instance of the bean by using the jakarta.annotation.Resource
annotation for resources or the jakarta.inject.Inject
annotation for CDI beans.
For the bean type, specify the class name of the interface the bean implements.
Predefined Bean | Resource or CDI Bean | Injection Example |
---|---|---|
|
Resource |
|
|
Resource |
|
|
Resource |
|
|
Resource |
|
|
CDI bean |
|
|
CDI bean |
|
|
CDI bean |
|
Predefined beans are injected with dependent scope and the predefined default qualifier @Default
.
For more information about injecting resources, see Resource Injection.
The following code snippet shows how to use the @Resource
and @Inject
annotations to inject predefined beans.
This code snippet injects a user transaction and a context object into the servlet class TransactionServlet
.
The user transaction is an instance of the predefined bean that implements the jakarta.transaction.UserTransaction
interface.
The context object is an instance of the predefined bean that implements the jakarta.servlet.ServletContext
interface.
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServlet;
import jakarta.transaction.UserTransaction;
...
public class TransactionServlet extends HttpServlet {
@Resource UserTransaction transaction;
@Inject ServletContext context;
...
}
Using Events in CDI Applications
Events allow beans to communicate without any compile-time dependency. One bean can define an event, another bean can fire the event, and yet another bean can handle the event. In addition, events can be fired asynchronously. The beans can be in separate packages and even in separate tiers of the application.
Defining Events
An event consists of the following:
-
The event object, a Java object
-
Zero or more qualifier types, the event qualifiers
For example, in the billpayment
example described in The billpayment Example: Using Events and Interceptors, a PaymentEvent
bean defines an event using three properties, which have setter and getter methods:
public String paymentType;
public BigDecimal value;
public Date datetime;
public PaymentEvent() {
}
The example also defines qualifiers that distinguish between two kinds of PaymentEvent
.
Every event also has the default qualifier @Any
.
Using Observer Methods to Handle Events
An event handler uses an observer method to consume events.
Each observer method takes as a parameter an event of a specific event type that is annotated with the @Observes
annotation and with any qualifiers for that event type.
The observer method is notified of an event if the event object matches the event type and if all the qualifiers of the event match the observer method event qualifiers.
The observer method can take other parameters in addition to the event parameter. The additional parameters are injection points and can declare qualifiers.
The event handler for the billpayment
example, PaymentHandler
, defines two observer methods, one for each type of PaymentEvent
:
public void creditPayment(@Observes @Credit PaymentEvent event) {
...
}
public void debitPayment(@Observes @Debit PaymentEvent event) {
...
}
Conditional and Transactional Observer Methods
Observer methods can also be conditional or transactional:
-
A conditional observer method is notified of an event only if an instance of the bean that defines the observer method already exists in the current context. To declare a conditional observer method, specify
notifyObserver=IF_EXISTS
as an argument to@Observes
:@Observes(notifyObserver=IF_EXISTS)
To obtain the default unconditional behavior, you can specify
@Observes(notifyObserver=ALWAYS)
. -
A transactional observer method is notified of an event during the before-completion or after-completion phase of the transaction in which the event was fired. You can also specify that the notification is to occur only after the transaction has completed successfully or unsuccessfully. To specify a transactional observer method, use any of the following arguments to
@Observes
:@Observes(during=BEFORE_COMPLETION) @Observes(during=AFTER_COMPLETION) @Observes(during=AFTER_SUCCESS) @Observes(during=AFTER_FAILURE)
To obtain the default nontransactional behavior, specify
@Observes(during=IN_PROGRESS)
.An observer method that is called before completion of a transaction may call the
setRollbackOnly
method on the transaction instance to force a transaction rollback.
Observer methods may throw exceptions. If a transactional observer method throws an exception, the exception is caught by the container. If the observer method is nontransactional, the exception terminates processing of the event, and no other observer methods for the event are called.
Observer Method Ordering
Before a certain observer event notification is generated, the container determines the order in which observer methods for that event are invoked.
Observer method order is established through the declaration of the @Priority
annotation on an event parameter of an observer method, as in the following example:
void afterLogin(@Observes @Priority(jakarta.interceptor.Interceptor.Priority.APPLICATION) LoggedInEvent event) { ... }
Note the following:
-
If the
@Priority
annotation is not specified, the default value isjakarta.interceptor.Interceptor.Priority.APPLICATION + 500
. -
If two or more observer methods are assigned the same priority, the order in which they are invoked is undefined and is therefore unpredictable.
Firing Events
Beans fire events by implementing an instance of the jakarta.enterprise.event.Event
interface.
Events can be fired synchronously or asynchronously.
Firing Events Synchronously
To activate an event synchronously, call the jakarta.enterprise.event.Event.fire
method.
This method fires an event and notifies any observer methods.
In the billpayment
example, a managed bean called PaymentBean
fires the appropriate event by using information it receives from the user interface.
There are actually four event beans, two for the event object and two for the payload.
The managed bean injects the two event beans.
The pay
method uses a switch
statement to choose which event to fire, using new
to create the payload.
@Inject
@Credit
Event<PaymentEvent> creditEvent;
@Inject
@Debit
Event<PaymentEvent> debitEvent;
private static final int DEBIT = 1;
private static final int CREDIT = 2;
private int paymentOption = DEBIT;
...
@Logged
public String pay() {
...
switch (paymentOption) {
case DEBIT:
PaymentEvent debitPayload = new PaymentEvent();
// populate payload ...
debitEvent.fire(debitPayload);
break;
case CREDIT:
PaymentEvent creditPayload = new PaymentEvent();
// populate payload ...
creditEvent.fire(creditPayload);
break;
default:
logger.severe("Invalid payment option!");
}
...
}
The argument to the fire
method is a PaymentEvent
that contains the payload.
The fired event is then consumed by the observer methods.
Firing Events Asynchronously
To activate an event asynchronously, call the jakarta.enterprise.event.Event.fireAsync
method.
This method calls all resolved asynchronous observers in one or more different threads.
@Inject Event<LoggedInEvent> loggedInEvent;
public void login() {
...
loggedInEvent.fireAsync( new LoggedInEvent(user) );
}
The invocation of the fireAsync()
method returns immediately.
When events are fired asynchronously, observer methods are notified asynchronously. Consequently, observer method ordering cannot be guaranteed, because observer method invocation and the firing of asynchronous events occur on separate threads.
Using Interceptors in CDI Applications
An interceptor is a class used to interpose in method invocations or lifecycle events that occur in an associated target class. The interceptor performs tasks, such as logging or auditing, that are separate from the business logic of the application and are repeated often within an application. Such tasks are often called cross-cutting tasks. Interceptors allow you to specify the code for these tasks in one place for easy maintenance. When interceptors were first introduced to the Jakarta EE platform, they were specific to enterprise beans. On the Jakarta EE platform, you can use them with Jakarta EE managed objects of all kinds, including managed beans.
For information on Jakarta EE interceptors, see Using Jakarta EE Interceptors.
An interceptor class often contains a method annotated @AroundInvoke
, which specifies the tasks the interceptor will perform when intercepted methods are invoked.
It can also contain a method annotated @PostConstruct
, @PreDestroy
, @PrePassivate
, or @PostActivate
, to specify lifecycle callback interceptors, and a method annotated @AroundTimeout
, to specify enterprise bean timeout interceptors.
An interceptor class can contain more than one interceptor method, but it must have no more than one method of each type.
Along with an interceptor, an application defines one or more interceptor binding types, which are annotations that associate an interceptor with target beans or methods.
For example, the billpayment
example contains an interceptor binding type named @Logged
and an interceptor named LoggedInterceptor
.
The interceptor binding type declaration looks something like a qualifier declaration, but it is annotated with jakarta.interceptor.InterceptorBinding
:
@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}
An interceptor binding also has the java.lang.annotation.Inherited
annotation, to specify that the annotation can be inherited from superclasses.
The @Inherited
annotation also applies to custom scopes (not discussed in this tutorial) but does not apply to qualifiers.
An interceptor binding type may declare other interceptor bindings.
The interceptor class is annotated with the interceptor binding as well as with the @Interceptor
annotation.
For an example, see The LoggedInterceptor Interceptor Class.
Every @AroundInvoke
method takes a jakarta.interceptor.InvocationContext
argument, returns a java.lang.Object
, and throws an Exception
.
It can call InvocationContext
methods.
The @AroundInvoke
method must call the proceed
method, which causes the target class method to be invoked.
Once an interceptor and binding type are defined, you can annotate beans and individual methods with the binding type to specify that the interceptor is to be invoked either on all methods of the bean or on specific methods.
For example, in the billpayment
example, the PaymentHandler
bean is annotated @Logged
, which means that any invocation of its business methods will cause the interceptor’s @AroundInvoke
method to be invoked:
@Logged
@SessionScoped
public class PaymentHandler implements Serializable {...}
However, in the PaymentBean
bean, only the pay
and reset
methods have the @Logged
annotation, so the interceptor is invoked only when these methods are invoked:
@Logged
public String pay() {...}
@Logged
public void reset() {...}
In order for an interceptor to be invoked in a CDI application, it must, like an alternative, be specified in the beans.xml
file.
For example, the LoggedInterceptor
class is specified as follows:
<interceptors>
<class>ee.jakarta.tutorial.billpayment.interceptors.LoggedInterceptor</class>
</interceptors>
If an application uses more than one interceptor, the interceptors are invoked in the order specified in the beans.xml
file.
The interceptors that you specify in the beans.xml
file apply only to classes in the same archive.
Use the @Priority
annotation to specify interceptors globally for an application that consists of multiple modules, as in the following example:
@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
Interceptors with lower priority values are called first.
You do not need to specify the interceptor in the beans.xml
file when you use the @Priority
annotation.
Using Decorators in CDI Applications
A decorator is a Java class that is annotated jakarta.decorator.Decorator
and that has a corresponding decorators
element in the beans.xml
file.
A decorator bean class must also have a delegate injection point, which is annotated jakarta.decorator.Delegate
.
This injection point can be a field, a constructor parameter, or an initializer method parameter of the decorator class.
Decorators are outwardly similar to interceptors. However, they actually perform tasks complementary to those performed by interceptors. Interceptors perform cross-cutting tasks associated with method invocation and with the lifecycles of beans, but cannot perform any business logic. Decorators, on the other hand, do perform business logic by intercepting business methods of beans. This means that instead of being reusable for different kinds of applications, as are interceptors, their logic is specific to a particular application.
For example, instead of using an alternative TestCoderImpl
class for the encoder
example, you could create a decorator as follows:
@Decorator
public abstract class CoderDecorator implements Coder {
@Inject
@Delegate
@Any
Coder coder;
public String codeString(String s, int tval) {
int len = s.length();
return "\"" + s + "\" becomes " + "\"" + coder.codeString(s, tval)
+ "\", " + len + " characters in length";
}
}
See The decorators Example: Decorating a Bean for an example that uses this decorator.
This simple decorator returns more detailed output than the encoded string returned by the CoderImpl.codeString
method.
A more complex decorator could store information in a database or perform some other business logic.
A decorator can be declared as an abstract class so that it does not have to implement all the business methods of the interface.
In order for a decorator to be invoked in a CDI application, it must, like an interceptor or an alternative, be specified in the beans.xml
file.
For example, the CoderDecorator
class is specified as follows:
<decorators>
<class>ee.jakarta.tutorial.decorators.CoderDecorator</class>
</decorators>
If an application uses more than one decorator, the decorators are invoked in the order in which they are specified in the beans.xml
file.
If an application has both interceptors and decorators, the interceptors are invoked first. This means, in effect, that you cannot intercept a decorator.
The decorators that you specify in the beans.xml
file apply only to classes in the same archive.
Use the @Priority
annotation to specify decorators globally for an application that consists of multiple modules, as in the following example:
@Decorator
@Priority(Interceptor.Priority.APPLICATION)
public abstract class CoderDecorator implements Coder { ... }
Decorators with lower priority values are called first.
You do not need to specify the decorator in the beans.xml
when you use the @Priority
annotation.
Using Stereotypes in CDI Applications
A stereotype is a kind of annotation, applied to a bean, that incorporates other annotations. Stereotypes can be particularly useful in large applications in which you have a number of beans that perform similar functions. A stereotype is a kind of annotation that specifies the following:
-
A default scope
-
Zero or more interceptor bindings
-
Optionally, a
@Named
annotation, guaranteeing default EL naming -
Optionally, an
@Alternative
annotation, specifying that all beans with this stereotype are alternatives
A bean annotated with a particular stereotype will always use the specified annotations, so you do not have to apply the same annotations to many beans.
For example, you might create a stereotype named Action
, using the jakarta.enterprise.inject.Stereotype
annotation:
@RequestScoped
@Secure
@Transactional
@Named
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
All beans annotated @Action
will have request scope, use default EL naming, and have the interceptor bindings @Transactional
and @Secure
.
You could also create a stereotype named Mock
:
@Alternative
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Mock {}
All beans with this annotation are alternatives.
It is possible to apply multiple stereotypes to the same bean, so you can annotate a bean as follows:
@Action
@Mock
public class MockLoginAction extends LoginAction { ... }
It is also possible to override the scope specified by a stereotype, simply by specifying a different scope for the bean.
The following declaration gives the MockLoginAction
bean session scope instead of request scope:
@SessionScoped
@Action
@Mock
public class MockLoginAction extends LoginAction { ... }
CDI makes available a built-in stereotype called Model
, which is intended for use with beans that define the model layer of a model-view-controller application architecture.
This stereotype specifies that a bean is both @Named
and @RequestScoped
:
@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface Model {}
Using the Built-In Annotation Literals
The following built-in annotations define a Literal
static nested class, which can be used as a convenience feature for creating instances of annotations:
-
jakarta.enterprise.inject.Any
-
jakarta.enterprise.inject.Default
-
jakarta.enterprise.inject.New
-
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
For example:
Default defaultLiteral = new Default.Literal();
RequestScoped requestScopedLiteral = RequestScoped.Literal.INSTANCE;
Initialized initializedForApplicationScoped = new Initialized.Literal(ApplicationScoped.class);
Initialized initializedForRequestScoped = Initialized.Literal.of(RequestScoped.class);
Using the Configurators Interfaces
The CDI 2.0 specification defines the following Configurators interfaces, which are used for dynamically defining and modifying CDI objects:
Interface | Description |
---|---|
|
Helps create and configure the following type metadata:
|
|
Helps configure an existing |
|
Helps configure a new |
|
Helps configure a new |
|
Helps configure an |
|
Helps configure a |