Note
|
This part still contains references to decorators and a few comments that should be moved to the CDI Full "concept" section to add specific features to full |
A bean is a source of contextual objects which define application state and/or logic. These objects are called contextual instances of the bean. The container creates and destroys these instances and associates them with the appropriate context. Contextual instances of a bean may be injected into other objects (including other bean instances) that execute in the same context. A bean may bear metadata defining its lifecycle and interactions with other beans.
A bean comprises the following attributes:
-
A (nonempty) set of bean types
-
A (nonempty) set of qualifiers
-
A scope
-
Optionally, a bean name
-
A set of interceptor bindings
-
A bean implementation
Furthermore, a bean may or may not be an alternative.
A bean developer provides the bean implementation by writing business logic in Java code. The developer then defines the remaining attributes by explicitly annotating the bean class, or by allowing them to be defaulted by the container, as specified in [implementation].
The bean types and qualifiers of a bean determine where its instances will be injected by the container, as defined in [injection_and_resolution].
The bean developer may also create interceptors and/or decorators or reuse existing interceptors and/or decorators. The interceptor bindings of a bean determine which interceptors will be applied at runtime. The bean types and qualifiers of a bean determine which decorators will be applied at runtime. Interceptors are defined by Java interceptors specification, and interceptor bindings are specified in [interceptors]. Decorators are defined in [decorators].
A bean is provided by the container with the following capabilities:
-
transparent creation and destruction and scoping to a particular context, specified in [contexts] and [lifecycle],
-
scoped resolution by bean type and qualifier annotation type when injected into a Java-based client, as defined by [typesafe_resolution],
-
lifecycle callbacks and automatic injection of other bean instances, specified in [implementation] and [injection_and_resolution],
-
method interception, callback interception, as defined in [interceptors], and
-
event notification, as defined in [events].
A bean type defines a client-visible type of the bean. A bean may have multiple bean types. For example, the following bean has four bean types:
public class BookShop
extends Business
implements Shop<Book> {
...
}
The bean types are BookShop
, Business
, Shop<Book>
and Object
.
The rules for determining the (unrestricted) set of bean types for a bean are defined in [managed_bean_types], [producer_method_types] and [producer_field_types].
All beans have the bean type java.lang.Object
.
The bean types of a bean are used by the rules of typesafe resolution defined in [typesafe_resolution].
Almost any Java type may be a bean type of a bean:
-
A bean type may be an interface, a concrete class or an abstract class, and may be declared final or have final methods.
-
A bean type may be a parameterized type with actual type parameters and type variables.
-
A bean type may be an array type. Two array types are considered identical only if the element type is identical.
-
A bean type may be a primitive type. Primitive types are considered to be identical to their corresponding wrapper types in
java.lang
. -
A bean type may be a raw type.
However, some Java types are not legal bean types :
-
A type variable is not a legal bean type.
-
A parameterized type that contains a wildcard type parameter is not a legal bean type.
-
An array type whose component type is not a legal bean type.
Note that certain additional restrictions are specified in [unproxyable] for beans with a normal scope, as defined in [normal_scope].
The bean types of a bean may be restricted by annotating the bean class or producer method or field with the annotation @jakarta.enterprise.inject.Typed
.
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book> {
...
}
When a @Typed
annotation is explicitly specified, only the types whose classes are explicitly listed using the value
member, together with java.lang.Object
, are bean types of the bean.
In the example, the bean has a two bean types: Shop<Book>
and Object
.
If a bean class or producer method or field specifies a @Typed
annotation, and the value
member specifies a class which does not correspond to a type in the unrestricted set of bean types of a bean, the container automatically detects the problem and treats it as a definition error.
A client of a bean may typecast its contextual reference to a bean to any bean type of the bean which is a Java interface. However, the client may not in general typecast its contextual reference to an arbitrary concrete bean type of the bean. For example, if our managed bean was injected to the following field:
@Inject Business biz;
Then the following typecast is legal:
Shop<Book> bookShop = (Shop<Book>) biz;
However, the following typecast is not legal and might result in an exception at runtime:
BookShop bookShop = (BookShop) biz;
For a given bean type, there may be multiple beans which implement the type.
For example, an application may have two implementations of the interface PaymentProcessor
:
class SynchronousPaymentProcessor
implements PaymentProcessor {
...
}
class AsynchronousPaymentProcessor
implements PaymentProcessor {
...
}
A client that needs a PaymentProcessor
that processes payments synchronously needs some way to distinguish between the two different implementations.
One approach would be for the client to explicitly specify the class that implements the PaymentProcessor
interface.
However, this approach creates a hard dependence between client and implementation - exactly what use of the interface was designed to avoid!
A qualifier type represents some client-visible semantic associated with a type that is satisfied by some implementations of the type (and not by others). For example, we could introduce qualifier types representing synchronicity and asynchronicity. In Java code, qualifier types are represented by annotations.
@Synchronous
class SynchronousPaymentProcessor
implements PaymentProcessor {
...
}
@Asynchronous
class AsynchronousPaymentProcessor
implements PaymentProcessor {
...
}
Finally, qualifier types are applied to injection points to distinguish which implementation is required by the client.
For example, when the container encounters the following injected field, an instance of SynchronousPaymentProcessor
will be injected:
@Inject @Synchronous PaymentProcessor paymentProcessor;
But in this case, an instance of AsynchronousPaymentProcessor
will be injected:
@Inject @Asynchronous PaymentProcessor paymentProcessor;
The container inspects the qualifier annotations and type of the injected attribute to determine the bean instance to be injected, according to the rules of typesafe resolution defined in [typesafe_resolution].
An injection point may even specify multiple qualifiers.
Qualifier types are also used as event selectors by event consumers, as defined in [events].
Three standard qualifier types are defined in the package jakarta.enterprise.inject
. In addition, the built-in qualifier type @Named
is defined by the package jakarta.inject
.
Every bean has the built-in qualifier @Any
, even if it does not explicitly declare this qualifier.
If a bean does not explicitly declare a qualifier other than @Named
or @Any
, the bean has exactly one additional qualifier, of type @Default
. This is called the default qualifier.
The following declarations are equivalent:
@Default
public class Order { ... }
public class Order { ... }
Both declarations result in a bean with two qualifiers: @Any
and @Default
.
The following declaration results in a bean with three qualifiers: @Any
, @Default
and @Named("ord")
.
@Named("ord")
public class Order { ... }
The default qualifier is also assumed for any injection point that does not explicitly declare a qualifier, as defined in [injection_point_default_qualifier].
The following declarations, in which the use of the @Inject
annotation identifies the constructor parameter as an injection point, are equivalent:
public class Order {
@Inject
public Order(@Default OrderProcessor processor) { ... }
}
public class Order {
@Inject
public Order(OrderProcessor processor) { ... }
}
A qualifier type is a Java annotation defined as @Retention(RUNTIME)
. Typically a qualifier type is defined as @Target({METHOD, FIELD, PARAMETER, TYPE})
.
A qualifier type may be declared by specifying the @jakarta.inject.Qualifier
meta-annotation.
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Synchronous {}
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Asynchronous {}
A qualifier type may define annotation members.
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface PayBy {
PaymentMethod value();
}
The qualifiers of a bean are declared by annotating the bean class or producer method or field with the qualifier types.
@LDAP
class LdapAuthenticator
implements Authenticator {
...
}
public class Shop {
@Produces @All
public List<Product> getAllProducts() { ... }
@Produces @WishList
public List<Product> getWishList() { ... }
}
Any bean may declare multiple qualifier types.
@Synchronous @Reliable
class SynchronousReliablePaymentProcessor
implements PaymentProcessor {
...
}
Qualifier types may be applied to injected fields (see [injected_fields]) to determine the bean that is injected, according to the rules of typesafe resolution defined in [typesafe_resolution].
@Inject @LDAP Authenticator authenticator;
A bean may only be injected to an injection point if it has all the qualifiers of the injection point.
@Inject @Synchronous @Reliable PaymentProcessor paymentProcessor;
@Inject @All List<Product> catalog;
@Inject @WishList List<Product> wishList;
Qualifier types may be applied to parameters of producer methods, initializer methods, disposer methods, observer methods or bean constructors (see [implementation]) to determine the bean instance that is passed when the method is called by the container. The container uses the rules of typesafe resolution defined in [typesafe_resolution] to determine values for these parameters.
For example, when the container encounters the following producer method, an instance of SynchronousPaymentProcessor
will be passed to the first parameter and an instance of AsynchronousPaymentProcessor
will be passed to the second parameter:
@Produces
PaymentProcessor getPaymentProcessor(@Synchronous PaymentProcessor sync,
@Asynchronous PaymentProcessor async) {
return isSynchronous() ? sync : async;
}
In some cases, it may be useful to have a repeated qualifier for your type safe resolution. A repeated qualifier behaves just as any other qualifier does. For example, the below qualifier is a repeatable qualifier
@Target({ PARAMETER, FIELD, METHOD, TYPE })
@Retention(RUNTIME)
@Documented
@Qualifier
@Repeatable(Locations.class)
public @interface Location {
String value();
}
@Target({ PARAMETER, FIELD, METHOD, TYPE })
@Retention(RUNTIME)
public @interface Locations {
Location[] value();
}
Now you can define appropriate producers and injection points for repeated qualifiers.
@Produces
@Location("north")
@Location("south")
public Coordinate createCoordinate() {
// ...
}
@Inject
@Location("north")
@Location("south")
private Coordinate coordinate;
A partial match injection point will still work in this case (from the same producer method)
@Inject
@Location("south")
private Coordinate coordinate;
However, adding the follow producer method will continue to give you an ambiguous resolution error (assuming the other producer exists as well)
@Produces
@Location("south")
public Coordinate createSouthCoordinate() {
// ...
}
Scoped objects, exist in a well-defined lifecycle context:
-
they may be automatically created when needed and then automatically destroyed when the context in which they were created ends, and
-
their state is automatically shared by clients that execute in the same context.
All beans have a scope. The scope of a bean determines the lifecycle of its instances, and which instances of the bean are visible to instances of other beans, as defined in [contexts]. A scope type is represented by an annotation type.
For example, an object that represents the current user is represented by a session scoped object:
@Produces @SessionScoped User getCurrentUser() { ... }
A list that contains the results of a search screen might be represented by a request scoped object:
@Produces @RequestScoped @Named("orders")
List<Order> getOrderSearchResults() { ... }
The set of scope types is extensible.
There are four standard scope types defined in {cdi_lite}, all defined in the package jakarta.enterprise.context
.
-
The container must provide an implementation of the @RequestScoped, @ApplicationScoped and @SessionScoped annotations defined in [builtin_contexts]. Note that these standard scopes can be extended by third-party extensions as defined in [context]
-
Finally, there is a
@Dependent
pseudo-scope for dependent objects, as defined in [dependent_context].
If an interceptor has any scope other than @Dependent
, non-portable behavior results.
A scope type is a Java annotation defined as @Retention(RUNTIME)
. Typically a scope type is defined as @Target({TYPE, METHOD, FIELD})
. All scope types must also specify the @jakarta.inject.Scope
or @jakarta.enterprise.context.NormalScope
meta-annotation.
A scope type must not have any attributes. If a scope type has attributes non-portable behavior results.
For example, the following annotation declares a "business process scope":
@Inherited
@NormalScope
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface BusinessProcessScoped {}
Custom scopes are normally defined by portable extensions, which must also provide a context object, as defined in [context], that implements the custom scope.
The scope of a bean is defined by annotating the bean class or producer method or field with a scope type.
A bean class or producer method or field may specify at most one scope type annotation. If a bean class or producer method or field specifies multiple scope type annotations, the container automatically detects the problem and treats it as a definition error.
public class Shop {
@Produces @ApplicationScoped @All
public List<Product> getAllProducts() { ... }
@Produces @SessionScoped @WishList
public List<Product> getWishList() { ..... }
}
Likewise, a bean with the custom business process scope may be declared by annotating it with the @BusinessProcessScoped
annotation:
@BusinessProcessScoped
public class Order { ... }
Alternatively, a scope type may be specified using a stereotype annotation, as defined in Declaring the stereotypes for a bean.
When no scope is explicitly declared by annotating the bean class or producer method or field the scope of a bean is defaulted.
The default scope for a bean which does not explicitly declare a scope depends upon its declared stereotypes:
-
If the bean does not declare any stereotype with a declared default scope, the default scope for the bean is
@Dependent
. -
If all stereotypes declared by the bean that have some declared default scope have the same default scope, then that scope is the default scope for the bean.
-
If there are two different stereotypes declared by the bean that declare different default scopes, then there is no default scope and the bean must explicitly declare a scope. If it does not explicitly declare a scope, the container automatically detects the problem and treats it as a definition error.
If a bean explicitly declares a scope, any default scopes declared by stereotypes are ignored.
The default bean discovery mode for a bean archive is annotated
, and such a bean archive is said to be an implicit bean archive as defined in [bean_archive].
If the bean discovery mode is annotated
then:
-
bean classes that don’t have bean defining annotation (as defined in Bean defining annotations) are not discovered, and
-
producer methods (as defined in [producer_method]) whose bean class does not have a bean defining annotation are not discovered, and
-
producer fields (as defined in [producer_field]) whose bean class does not have a bean defining annotation are not discovered, and
-
disposer methods (as defined in [disposer_method]) whose bean class does not have a bean defining annotation are not discovered, and
-
observer methods (as defined in [observes]) whose bean class does not have a bean defining annotation are not discovered.
A bean class may have a bean defining annotation, allowing it to be placed anywhere in an application, as defined in [bean_archive]. A bean class with a bean defining annotation is said to be an implicit bean.
The set of bean defining annotations contains:
-
@ApplicationScoped
,@SessionScoped
,@ConversationScoped
and@RequestScoped
annotations, -
all other normal scope types,
-
@Interceptor
annotation, -
all stereotype annotations (i.e. annotations annotated with
@Stereotype
), -
and the
@Dependent
scope annotation.
If one of these annotations is declared on a bean class, then the bean class is said to have a bean defining annotation. For example, this dependent scoped bean has a bean defining annotation:
@Dependent
public class BookShop
extends Business
implements Shop<Book> {
...
}
whilst this dependent scoped bean does not have a bean defining annotation:
public class CoffeeShop
extends Business
implements Shop<Coffee> {
...
}
Note that to ensure compatibility with other Jakarta Dependency Injection implementations, all pseudo-scope annotations except @Dependent
are not bean defining annotations.
However, a stereotype annotation including a pseudo-scope annotation is a bean defining annotation.
A bean may have a bean name. A bean with a name may be referred to by its name when used in a non typesafe environment (like the Unified Expression Language). A valid bean name is a period-separated list of valid EL identifiers.
The following strings are valid bean names:
com.acme.settings
orderManager
Subject to the restrictions defined in [ambig_names], multiple beans may share the same bean name.
Bean names are used by the rules of bean name resolution defined in [name_resolution].
To specify the name of a bean, the qualifier @jakarta.inject.Named
is applied to the bean class or producer method or field.
This bean is named currentOrder
:
@Named("currentOrder")
public class Order { ... }
In the following circumstances, a default name must be assigned by the container:
-
A bean class or producer method or field of a bean declares a
@Named
annotation and no bean name is explicitly specified by thevalue
member. -
A bean declares a stereotype that declares an empty
@Named
annotation, and the bean does not explicitly specify a bean name.
The default name for a bean depends upon the kind of the bean. The rules for determining the default name for a bean are defined in [managed_bean_name], [producer_method_name] and [producer_field_name].
An alternative is a bean that must be explicitly selected if it should be available for lookup, injection or name resolution.
An alternative may be declared by annotating the bean class or producer method or field with the @Alternative
annotation.
@Alternative
public class MockOrder extends Order { ... }
Alternatively, an alternative may be declared by annotating a bean, producer method or producer field with a stereotype that declares an @Alternative
annotation.
If an interceptor or decorator is an alternative, non-portable behavior results.
In many systems, use of architectural patterns produces a set of recurring bean roles. A stereotype allows a framework developer to identify such a role and declare some common metadata for beans with that role in a central place.
A stereotype encapsulates any combination of:
-
a default scope, and
-
a set of interceptor bindings.
A stereotype may also specify that:
-
all beans with the stereotype have defaulted bean names, or that
-
all beans with the stereotype are alternatives.
A bean may declare zero, one or multiple stereotypes.
A bean stereotype is a Java annotation defined as @Retention(RUNTIME)
. Typically a bean stereotype is defined as @Target({TYPE, METHOD, FIELD})
, @Target(TYPE)
, @Target(METHOD)
, @Target(FIELD)
or @Target({METHOD, FIELD})
.
A stereotype may be declared by specifying the @jakarta.enterprise.inject.Stereotype
meta-annotation.
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
The default scope of a stereotype is defined by annotating the stereotype with a scope type. A stereotype may declare at most one scope. If a stereotype declares more than one scope, the container automatically detects the problem and treats it as a definition error.
For example, the following stereotype might be used to identify action classes in a web application:
@RequestScoped
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
Then actions would have scope @RequestScoped
unless the scope is explicitly specified by the bean.
The interceptor bindings of a stereotype are defined by annotating the stereotype with the interceptor binding types. A stereotype may declare zero, one or multiple interceptor bindings, as defined in [stereotype_interceptor_bindings].
We may specify interceptor bindings that apply to all actions:
@RequestScoped
@Secure
@Transactional
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
A stereotype may declare an empty @Named
annotation, which specifies that every bean with the stereotype has a defaulted name when a name is not explicitly specified by the bean.
A @Named
qualifier declared by a stereotype is not added to the qualifiers of a bean with the stereotype.
If a stereotype declares a non-empty @Named
annotation, the container automatically detects the problem and treats it as a definition error.
We may specify that all actions have bean names:
@RequestScoped
@Secure
@Transactional
@Named
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
A stereotype should not declare any qualifier annotation other than @Named
. If a stereotype declares any other qualifier annotation, non-portable behavior results.
A stereotype should not be annotated @Typed
. If a stereotype is annotated @Typed
, non-portable behavior results.
A stereotype may declare an @Alternative
annotation, which specifies that every bean with the stereotype is an alternative.
We may specify that all mock objects are alternatives:
@Alternative
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Mock {}
A stereotype may declare other stereotypes.
@Auditable
@Action
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface AuditableAction {}
Stereotype declarations are transitive - a stereotype declared by a second stereotype is inherited by all beans and other stereotypes that declare the second stereotype.
Stereotypes declared @Target(TYPE)
may not be applied to stereotypes declared @Target({TYPE, METHOD, FIELD})
, @Target(METHOD)
, @Target(FIELD)
or @Target({METHOD, FIELD})
.
Stereotype annotations may be applied to a bean class or producer method or field.
@Action
public class LoginAction { ... }
The default scope declared by the stereotype may be overridden by the bean:
@Mock @ApplicationScoped @Action
public class MockLoginAction extends LoginAction { ... }
Multiple stereotypes may be applied to the same bean:
@Dao @Action
public class LoginAction { ... }
The built-in stereotype @jakarta.enterprise.inject.Model
is intended for use with beans that define the model layer of an MVC web application architecture such as JSF:
@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface Model {}
In addition, the special-purpose @Interceptor
stereotype is defined in [declaring_interceptor].
When the application violates a rule defined by this specification, the container automatically detects the problem. There are three kinds of problem:
-
Definition errors - occur when a single bean definition violates the rules of this specification. If a definition error exists, the container must throw a subclass of
jakarta.enterprise.inject.spi.DefinitionException
. -
Deployment problems - occur when there are problems resolving dependencies, or inconsistent specialization, in a particular deployment. If a deployment problem occurs, the container must throw a subclass of
jakarta.enterprise.inject.spi.DeploymentException
. -
Exceptions - occur at runtime
Definition errors are developer errors. They may be detected by tooling at development time, and are also detected by the container at initialization time. If a definition error exists in a deployment, initialization will be aborted by the container.
Deployment problems are detected by the container at initialization time. If a deployment problem exists in a deployment, initialization will be aborted by the container.
The container is permitted to define a non-portable mode, for use at development time, in which some definition errors and deployment problems do not cause application initialization to abort.
Exceptions represent problems that may not be detected until they actually occur at runtime. All exceptions defined by this specification are unchecked exceptions. All exceptions defined by this specification may be safely caught and handled by the application.