Skip to content

Latest commit

 

History

History
669 lines (431 loc) · 23.2 KB

implementation.asciidoc

File metadata and controls

669 lines (431 loc) · 23.2 KB

Programming model

The container provides built-in support for injection and contextual lifecycle management of the following kinds of bean:

  • Managed beans

  • Producer methods and fields

All containers must support managed beans, producer methods and producer fields.

A portable extension, as well as a build compatible extension, may provide other kinds of beans.

Managed beans

A managed bean is a bean that is implemented by a Java class. This class is called the bean class of the managed bean. The basic lifecycle and semantics of managed beans are defined by the Managed Beans specification.

If a managed bean has a non-static public field, it must have scope @Dependent. If a managed bean with a non-static public field declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error.

If the managed bean class is a generic type, it must have scope @Dependent. If a managed bean with a parameterized bean class declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error.

Which Java classes are managed beans?

A Java class is a managed bean if it meets all of the following conditions:

  • It is not an inner class.

  • It is a non-abstract class.

  • It does not implement jakarta.enterprise.inject.spi.Extension.

  • It is not annotated @Vetoed or in a package annotated @Vetoed.

  • It has an appropriate constructor - either:

    • the class has a constructor with no parameters, or

    • the class declares a constructor annotated @Inject.

In {cdi_full} environment, a Java class is a managed bean also if:

  • It is an abstract or non-abstract class annotated @Decorator.

All Java classes that meet these conditions are managed beans and thus no special declaration is required to define a managed bean.

If packages annotated @Vetoed are split across classpath entries, non-portable behavior results. An application can prevent packages being split across jars by sealing the package as defined by the JAR File Specification.

Bean types of a managed bean

The unrestricted set of bean types for a managed bean contains the bean class, every superclass and all interfaces it implements directly or indirectly.

The resulting set of bean types for a managed bean consists only of legal bean types, all other types are removed from the set of bean types.

Note the additional restrictions upon bean types of beans with normal scopes defined in Unproxyable bean types.

Declaring a managed bean

A managed bean with a constructor that takes no parameters does not require any special annotations. The following classes are beans:

public class Shop { .. }
class PaymentProcessorImpl implements PaymentProcessor { ... }

If the managed bean does not have a constructor that takes no parameters, it must have a constructor annotated @Inject. No additional special annotations are required.

A bean class may specify a scope, bean name, stereotypes and/or qualifiers:

@ConversationScoped @Default
public class ShoppingCart { ... }

A managed bean may extend another managed bean:

@Named("loginAction")
public class LoginAction { ... }
@Mock
@Named("loginAction")
public class MockLoginAction extends LoginAction { ... }

The second bean is a "mock object" that overrides the implementation of LoginAction when running in an embedded CDI based integration testing environment.

Default bean name for a managed bean

The default name for a managed bean is the unqualified class name of the bean class, after converting the first character to lower case.

For example, if the bean class is named ProductList, the default bean name is productList.

Producer methods

A producer method acts as a source of objects to be injected, where:

  • the objects to be injected are not required to be instances of beans, or

  • the concrete type of the objects to be injected may vary at runtime, or

  • the objects require some custom initialization that is not performed by the bean constructor.

A producer method must be a default-access, public, protected or private, non-abstract method of a managed bean class. A producer method may be either static or non-static.

If a producer method sometimes returns a null value, then the producer method must have scope @Dependent. If a producer method returns a null value at runtime, and the producer method declares any other scope, an IllegalProductException is thrown by the container. This restriction allows the container to use a client proxy, as defined in [client_proxies].

If the producer method return type is a parameterized type, it must specify an actual type parameter or type variable for each type parameter.

If a producer method return type contains a wildcard type parameter or is an array type whose component type contains a wildcard type parameter, the container automatically detects the problem and treats it as a definition error.

If the producer method return type is a parameterized type with a type variable, it must have scope @Dependent. If a producer method with a parameterized return type with a type variable declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error.

If a producer method return type is a type variable or an array type whose component type is a type variable, the container automatically detects the problem and treats it as a definition error.

The application may call producer methods directly. However, if the application calls a producer method directly, no parameters will be passed to the producer method by the container; the returned object is not bound to any context; and its lifecycle is not managed by the container.

A bean may declare multiple producer methods.

Bean types of a producer method

The bean types of a producer method depend upon the method return type:

  • If the return type is an interface, the unrestricted set of bean types contains the return type, all interfaces it extends directly or indirectly and java.lang.Object.

  • If a return type is primitive or is a Java array type, the unrestricted set of bean types contains exactly two types: the method return type and java.lang.Object.

  • If the return type is a class, the unrestricted set of bean types contains the return type, every superclass and all interfaces it implements directly or indirectly.

The resulting set of bean types for a producer method consists only of legal bean types, all other types are removed from the set of bean types.

Note the additional restrictions upon bean types of beans with normal scopes defined in Unproxyable bean types.

Declaring a producer method

A producer method may be declared by annotating a method with the @jakarta.enterprise.inject.Produces annotation.

public class Shop {
   @Produces PaymentProcessor getPaymentProcessor() { ... }
   @Produces List<Product> getProducts() { ... }
}

A producer method may also specify scope, bean name, stereotypes and/or qualifiers.

public class Shop {
   @Produces @ApplicationScoped @Catalog @Named("catalog")
   List<Product> getProducts() { ... }
}

If a producer method is annotated @Inject, has a parameter annotated @Disposes, has a parameter annotated @Observes, or has a parameter annotated @ObservesAsync, the container automatically detects the problem and treats it as a definition error.

Interceptors may not declare producer methods. If an interceptor has a method annotated @Produces, the container automatically detects the problem and treats it as a definition error.

A producer method may have any number of parameters. All producer method parameters are injection points.

public class OrderFactory {

   @Produces @ConversationScoped
   public Order createCurrentOrder(Shop shop, @Selected Product product) {
       Order order = new Order(product, shop);
       return order;
   }

}

Default bean name for a producer method

The default name for a producer method is the method name, unless the method follows the JavaBeans property getter naming convention, in which case the default name is the JavaBeans property name.

For example, this producer method is named products:

@Produces @Named
public List<Product> getProducts() { ... }

This producer method is named paymentProcessor:

@Produces @Named
public PaymentProcessor paymentProcessor() { ... }

Producer fields

A producer field is a slightly simpler alternative to a producer method.

A producer field must be a default-access, public, protected or private, field of a managed bean class. A producer field may be either static or non-static.

If a producer field sometimes contains a null value when accessed, then the producer field must have scope @Dependent. If a producer field contains a null value at runtime, and the producer field declares any other scope, an IllegalProductException is thrown by the container. This restriction allows the container to use a client proxy, as defined in [client_proxies].

If the producer field type is a parameterized type, it must specify an actual type parameter or type variable for each type parameter.

If a producer field type contains a wildcard type parameter or is an array type whose component type contains a wildcard parameter, the container automatically detects the problem and treats it as a definition error.

If the producer field type is a parameterized type with a type variable, it must have scope @Dependent. If a producer field with a parameterized type with a type variable declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error.

If a producer field type is a type variable or is an array type whose component type is a type variable, the container automatically detects the problem and treats it as a definition error.

The application may access producer fields directly. However, if the application accesses a producer field directly, the returned object is not bound to any context; and its lifecycle is not managed by the container.

A bean may declare multiple producer fields.

Bean types of a producer field

The bean types of a producer field depend upon the field type:

  • If the field type is an interface, the unrestricted set of bean types contains the field type, all interfaces it extends directly or indirectly and java.lang.Object.

  • If a field type is primitive or is a Java array type, the unrestricted set of bean types contains exactly two types: the field type and java.lang.Object.

  • If the field type is a class, the unrestricted set of bean types contains the field type, every superclass and all interfaces it implements directly or indirectly.

The resulting set of bean types for a producer field consists only of legal bean types, all other types are removed from the set of bean types.

Note the additional restrictions upon bean types of beans with normal scopes defined in Unproxyable bean types.

Declaring a producer field

A producer field may be declared by annotating a field with the @jakarta.enterprise.inject.Produces annotation.

public class Shop {
   @Produces PaymentProcessor paymentProcessor = ....;
   @Produces List<Product> products = ....;
}

A producer field may also specify scope, bean name, stereotypes and/or qualifiers.

public class Shop {
   @Produces @ApplicationScoped @Catalog @Named("catalog")
   List<Product> products = ....;
}

If a producer field is annotated @Inject, the container automatically detects the problem and treats it as a definition error.

Interceptors may not declare producer fields. If an interceptor has a field annotated @Produces, the container automatically detects the problem and treats it as a definition error.

Default bean name for a producer field

The default name for a producer field is the field name.

For example, this producer field is named products:

@Produces @Named
public List<Product> products = ...;

Disposer methods

A disposer method allows the application to perform customized cleanup of an object returned by a producer method or producer field.

A disposer method must be a default-access, public, protected or private, non-abstract method of a managed bean class. A disposer method may be either static or non-static.

A bean may declare multiple disposer methods.

Disposed parameter of a disposer method

Each disposer method must have exactly one disposed parameter, of the same type as the corresponding producer method return type or producer field type. When searching for disposer methods for a producer method or producer field, the container considers the type and qualifiers of the disposed parameter. If a producer method or producer field declared by the same bean class is assignable to the disposed parameter, according to the rules of typesafe resolution defined in [typesafe_resolution], the container must call this method when destroying any instance returned by that producer method or producer field.

A disposer method may resolve to multiple producer methods or producer fields declared by the bean class, in which case the container must call it when destroying any instance returned by any of these producer methods or producer fields.

Declaring a disposer method

A disposer method may be declared by annotating a parameter @jakarta.enterprise.inject.Disposes. That parameter is the disposed parameter. Qualifiers may be declared by annotating the disposed parameter:

public class UserDatabaseEntityManager {

    @Produces @ConversationScoped @UserDatabase
    public EntityManager create(EntityManagerFactory emf) {
        return emf.createEntityManager();
    }

    public void close(@Disposes @UserDatabase EntityManager em) {
        em.close();
    }

}
public class Resources {

    private EntityManagerFactory emf;

    @PostConstruct
    public void setupEntityManagerFactory() {
        emf = Persistence.createEntityManagerFactory("userDatabase");
    }

    @Produces @UserDatabase
    public EntityManager start() {
        return emf.createEntityManager();
    }

    public void close(@Disposes @UserDatabase EntityManager em) {
        em.close();
    }

}

If a method has more than one parameter annotated @Disposes, the container automatically detects the problem and treats it as a definition error.

If a disposer method is annotated @Produces or @Inject, has a parameter annotated @Observes or has a parameter annotated @ObservesAsync, the container automatically detects the problem and treats it as a definition error.

Interceptors may not declare disposer methods. If an interceptor has a method annotated @Disposes, the container automatically detects the problem and treats it as a definition error.

In addition to the disposed parameter, a disposer method may declare additional parameters, which may also specify qualifiers. These additional parameters are injection points.

public void close(@Disposes @UserDatabase EntityManager em, Logger log) { ... }

Disposer method resolution

A disposer method is bound to a producer method or producer field if:

  • the producer method or producer field is declared by the same bean class as the disposer method, and

  • the producer method or producer field is assignable to the disposed parameter, according to the rules of typesafe resolution defined in [typesafe_resolution] (using [assignable_parameters]).

If there are multiple disposer methods for a single producer method or producer field, the container automatically detects the problem and treats it as a definition error.

If there is no producer method or producer field declared by the bean class that is assignable to the disposed parameter of a disposer method, the container automatically detects the problem and treats it as a definition error.

Bean constructors

When the container instantiates a bean class, it calls the bean constructor. The bean constructor is a default-access, public, protected or private constructor of the bean class.

The application may call bean constructors directly. However, if the application directly instantiates the bean, no parameters are passed to the constructor by the container; the returned object is not bound to any context; no dependencies are injected by the container; and the lifecycle of the new instance is not managed by the container.

Declaring a bean constructor

The bean constructor may be identified by annotating the constructor @Inject.

@SessionScoped
public class ShoppingCart implements Serializable {

   private User customer;

   @Inject
   public ShoppingCart(User customer) {
       this.customer = customer;
   }

   public ShoppingCart(ShoppingCart original) {
       this.customer = original.customer;
   }

   ShoppingCart() {}

   ...

}
@ConversationScoped
public class Order {

   private Product product;
   private User customer;

   @Inject
   public Order(@Selected Product product, User customer) {
       this.product = product;
       this.customer = customer;
   }

   public Order(Order original) {
       this.product = original.product;
       this.customer = original.customer;
   }

   Order() {}

   ...

}

If a bean class does not explicitly declare a constructor using @Inject, the constructor that accepts no parameters is the bean constructor.

If a bean class has more than one constructor annotated @Inject, the container automatically detects the problem and treats it as a definition error.

If a bean constructor has a parameter annotated @Disposes, @Observes, or @ObservesAsync, the container automatically detects the problem and treats it as a definition error.

A bean constructor may have any number of parameters. All parameters of a bean constructor are injection points.

Injected fields

An injected field is a non-static, non-final field of a bean class or of any other classes supporting injection.

Declaring an injected field

An injected field may be declared by annotating the field @jakarta.inject.Inject.

@ConversationScoped
public class Order {

   @Inject @Selected Product product;
   @Inject User customer;

}

If an injected field is annotated @Produces, the container automatically detects the problem and treats it as a definition error.

Initializer methods

An initializer method is a default-access, public, protected or private, non-abstract, non-static, non-generic method of a bean class or of any other classes supporting injection.

A bean class may declare multiple (or zero) initializer methods.

Method interceptors are never called when the container calls an initializer method.

The application may call initializer methods directly, but then no parameters will be passed to the method by the container.

Declaring an initializer method

An initializer method may be declared by annotating the method @jakarta.inject.Inject.

@ConversationScoped
public class Order {

   private Product product;
   private User customer;

   @Inject
   void setProduct(@Selected Product product) {
       this.product = product;
   }

   @Inject
   public void setCustomer(User customer) {
       this.customer = customer;
   }

}

If a generic method of a bean is annotated @Inject, the container automatically detects the problem and treats it as a definition error.

If an initializer method is annotated @Produces, has a parameter annotated @Disposes, has a parameter annotated @Observes, or has a parameter annotated @ObservesAsync, the container automatically detects the problem and treats it as a definition error.

An initializer method may have any number of parameters. All initializer method parameters are injection points.

The default qualifier at injection points

If an injection point declares no qualifier, the injection point has exactly one qualifier, the default qualifier @Default.

The following are equivalent:

@ConversationScoped
public class Order {

   private Product product;
   private User customer;

   @Inject
   public void init(@Selected Product product, User customer) {
       this.product = product;
       this.customer = customer;
   }

}
@ConversationScoped
public class Order {

   private Product product;
   private User customer;

   @Inject
   public void init(@Selected Product product, @Default User customer) {
       this.product = product;
       this.customer = customer;
   }

}

The following definitions are equivalent:

public class Payment {

   public Payment(BigDecimal amount) { ... }

   @Inject Payment(Order order) {
      this(order.getAmount();
   }

}
public class Payment {

   public Payment(BigDecimal amount) { ... }

   @Inject Payment(@Default Order order) {
      this(order.getAmount();
   }

}

Finally, the following are equivalent:

@Inject Order order;
@Inject @Default Order order;

The qualifier @Named at injection points

The use of @Named as an injection point qualifier is not recommended, except in the case of integration with legacy code that uses string-based names to identify beans.

If an injected field declares a @Named annotation that does not specify the value member, the name of the field is assumed. For example, the following field has the qualifier @Named("paymentService"):

@Inject @Named PaymentService paymentService;

If any other injection point declares a @Named annotation that does not specify the value member, the container automatically detects the problem and treats it as a definition error.

Unproxyable bean types

The container uses proxies to provide certain functionality. Certain legal bean types cannot be proxied by the container:

  • classes which don’t have a non-private constructor with no parameters,

  • classes which are declared final,

  • classes which have non-static, final methods with public, protected or default visibility,

  • primitive types,

  • and array types.

A bean type must be proxyable if an injection point resolves to a bean:

  • that requires a client proxy, or

  • that has a bound interceptor.

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