Skip to content

Latest commit

 

History

History
953 lines (666 loc) · 30.7 KB

definition.asciidoc

File metadata and controls

953 lines (666 loc) · 30.7 KB

Concepts

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 or reuse existing interceptors. The interceptor bindings of a bean determine which interceptors will be applied at runtime. Interceptors are defined by Jakarta EE interceptors specification, and interceptor bindings are specified in [interceptors].

In {cdi_full} environment, the bean developer may also create decorators or reuse existing decorators. The bean types and qualifiers of a bean determine which decorators will be applied at runtime. Decorators are defined in [decorators].

Functionality provided by the container to the bean

A bean is provided by the container with the following capabilities:

In {cdi_full} environment, the container also provides the following capabilities:

Bean types

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].

Restricting the bean types of a bean

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.

Typecasting between bean types

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;

Qualifiers

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].

In {cdi_full} environment, qualifier types are also used to bind decorators to beans, as specified in [decorators].

Built-in qualifier types

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) { ... }
}

Defining new qualifier types

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();
}

Declaring the qualifiers of a bean

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 {
    ...
}

Specifying qualifiers of an injected field

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;

Specifying qualifiers of a method or constructor parameter

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;
}

Repeating qualifiers

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() {
   // ...
}

Scopes

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

An object that represents an order is represented by a conversation scoped object:

@ConversationScoped
public class Order { ... }
Note

Conversations are only available in {cdi_full}.

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.

Built-in scope types

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.

Defining new scope types

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 extensions, which must also provide an implementation of the Context interface, as defined in [context], that implements the custom scope. Portable extensions provide a context object directly, while build compatible extensions provide a class that the container has to instantiate to obtain the context object.

Declaring the bean 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.

Default scope

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 present on the bean, directly, indirectly, or transitively, 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.

Default bean discovery mode

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.

Bean defining annotations

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

Bean names

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].

Declaring the bean name

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 { ... }

Default bean names

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 the value 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].

Beans with no name

If @Named is not declared by the bean, nor by its stereotypes, a bean has no name.

If an interceptor has a name, non-portable behavior results.

Alternatives

An alternative is a bean that must be explicitly selected if it should be available for lookup, injection or name resolution.

Declaring an alternative

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 is an alternative, non-portable behavior results.

Stereotypes

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, or that

  • all beans with the stereotype have predefined @Priority.

A bean may declare zero, one or multiple stereotypes.

Defining new 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 {}
Declaring the default scope for a stereotype

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.

Specifying interceptor bindings for a stereotype

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 {}
Declaring a @Named stereotype

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.

Declaring an @Alternative stereotype

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 {}
Declaring stereotype with @Priority

A stereotype may declare a @Priority annotation which functions as a means of enabling and ordering affected beans.

If there are two different stereotypes present on a bean, directly, indirectly, or transitively, that declare different priority values, then the bean must explicitly declare a @Priority annotation. If the bean does not explicitly declare priority, the container automatically detects the problem and treats it as a definition error.

If a bean explicitly declares priority, any priority values declared by stereotypes are ignored.

Following sample shows a stereotype that can be used to mark bean as globally enabled alternative:

@Alternative
@Priority(Interceptor.Priority.APPLICATION + 5)
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Mock {}
Stereotypes with additional stereotypes

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

Declaring the stereotypes for a bean

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 { ... }

Built-in stereotypes

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].

Problems detected automatically by the container

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 {cdi_full}), 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.