Next Presso (CDI, Java EE and friends)

How to recognize different types of beans from quite a long way away

Posted by Antoine Sabot-Durand on Dec 14, 2015 | Comments
the larch

In CDI, Beans are a very centric concept. Yet, for a lot of user, this concept stays fuzzy and requires experiment to achieve an expected result. In this article I’ll try to clarify most of bean related concepts and detail the hidden mechanism behind bean definition and injection.

Bean, contextual instance and typesafe resolution

When most CDI users write

@Inject
@MyQualifier
MyBean bean;

they think: "I have injected the MyBean bean having @MyQualifier qualifier".

That’s not correct and it’s important to understand the exact mechanism behind this injection point definition.

Bean vs contextual instances

One of the specific feature in CDI is the fact that all components (qualifiers, beans, producers, etc..) are discovered at deployment time.

It allows the container to raise errors very early (before runtime) and for you to be sure that all injection points you defined will be satisfied and not ambiguous.

While this discovery process is not the topic of this article you should know that all classes packaged with your application will be analyzed at deployment to discover beans (and other components).

At the end of this discovery task, the container had created collections of meta-data for most elements included in CDI SPI. The more centric meta-data created by CDI container is the collection of Bean<T> discovered during deployment. These metadata are the real applications beans and in basic CDI usage you’ll never use them.

So don’t mix beans and the contextual instances (instances of the bean for a given context) you request to the container when adding an injection point in your code.

The content of Bean<T> interface

The Bean interface has two main functions:

  • Providing a "recipe" to create and destroy contextual instances (methods from Contextual<T>)

  • Storing bean metadata obtained from bean definition (methods from BeanAttributes<T>)

Bean Interface hierarchy, yes Interceptor and Decorator are also Beans
Bean Interface hierarchy, yes Interceptor and Decorator are also Beans

The metadata stored in Bean<T> come from the user code defining the bean (type and annotations). If you take a look at BeanAttributes in the above schema, you’ll see that these metadata include a set of types (yes a bean as multiple types) and a set of qualifiers (each bean has at least 2 qualifiers: @Default and @Any). These 2 sets are used in the CDI typesafe resolution mechanism.

Typesafe resolution for Dummies

When you use @Inject in your code, you’re asking the container to look for a certain Bean. The search is done by using info in Bean metadata.

For most injection point this search is done at deployment time to check if each injection point is satisfied and not ambiguous, the only exception is the programmatic lookup (use of Instance<T>). This approach allows the implementation to cache the matching bean for a given injection point.

When the matching Bean is found, the container use its create method to provide you an instance.

This process, called the Typesafe resolution can be simplified like this:

When resolving bean for a given injection point the container considers the set of types and qualifiers of all enabled beans to find the right candidate.

A simplified version of typesafe resolution
A simplified version of typesafe resolution

The actual process is a bit more complex with integration of Alternatives, but the general idea is here.

If the container succeeds in resolving the injection point by finding one and only one eligible bean, the create() method of this bean will be used to provide an instance for it.

So when do we refer to the Bean<T>?

In basic CDI, the answer is "never" (or almost).

Bean<T> will be used 90% of the time in portable extension to create a custom bean or analyse bean metadata.

Since CDI 1.1 you can also use Bean<T> outside extensions.

For the sake of reflection it is now allowed to inject the bean meta-data in a bean class, an interceptor or a decorator, allowing them to have info on metadata of the current bean.

For instance this interceptor use the meta-data of the intercepted bean to avoid issue with proxy creation in the implementation:

@Loggable
@Interceptor
public class LoggingInterceptor {

    @Inject
    private Logger logger;

    @Inject @Intercepted (1)
    private Bean<?> intercepted;

    @AroundInvoke
    private Object intercept(InvocationContext ic) throws Exception {
        logger.info(">> " + intercepted.getBeanClass().getName() + " - " + ic.getMethod().getName()); (2)
        try {
            return ic.proceed();
        } finally {
            logger.info("<< " + intercepted.getBeanClass().getName() + " - " + ic.getMethod().getName());
        }
    }
}
1 @Intercepted is a reserved qualifier to inject the intercepted bean in an interceptor
2 here it is used to retrieve the actual class of the contextual instance not the proxy’s class implementation may have created

Different kinds of CDI beans

Now that we stated the difference between Bean and Bean in stances, it’s time to list all the bean kind we’ve got in CDI and their specific behaviour.

Managed beans

Managed bean are the most obvious kind of bean available in CDI. They are defined by a class declaration.

According to the specification (section 3.1.1 Which Java classes are managed beans?):

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

  • It is not a non-static inner class.

  • It is a concrete class, or is annotated @Decorator.

  • It does not implement javax.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.

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

— CDI 1.2 specification

That’s for the general rules, a valid class can also be ignored if the bean discovery mode is set to none or annotated and the class doesn’t have a bean defining annotation.

To sum up, if you’re in the default bean discovery mode (Annotated) your class should follow the condition above and have at least one of the following annotation to become a CDI managed bean:

  • @ApplicationScoped, @SessionScoped, @ConversationScoped and @RequestScoped annotations,

  • all other normal scope types,

  • @Interceptor and @Decorator annotations,

  • all stereotype annotations (i.e. annotations annotated with @Stereotype),

  • and the @Dependent scope annotation.

Another limitation is linked to client proxies. In a lot of occasion (interceptor or decorator, passivation, usage of normal scope, possible circularity), the container may need to provide a contextual instance wrapped in a proxy. For this reason, managed bean classes should be proxyable or the container will raise an exception.

Thus in addition to the above rules the spec also restrictions on managed bean class to support certain services or be in normal scopes.

So, if possible you should avoid the following limitation on your bean class to be sure that they can be proxyable:

  • it should have a non private constructor with parameters,

  • it shouldn’t be final,

  • it shouldn’t have non static final methods.

Bean types of a managed bean

The set of bean types (used during typesafe resolution) for a given managed bean contains:

  • the bean class,

  • evey superclass (including Object),

  • all interface the class implements directly or indirectly.

Keep in mind that @Typed annotation can restrict this set. When it’s used, only the types whose classes are explicitly listed using the value member, together with Object, are bean types of the bean.

Session beans

CDI Session beans are EJB in CDI flavor. If you define a session bean with EJB 3.x client view in a bean archive without @Vetoed annotation on it (or on its package) you’ll have a Session Bean at runtime.

Local stateless, singleton or stateful EJB are automatically treated as CDI session bean: they support injection, CDI scope, interception, decoration and all other CDI services. Remote EJB and MDB cannot be used as CDI beans.

Note the following restriction regarding EJB and CDI scopes:

  • Stateless session beans must belong to the @Dependent scope,

  • Singleton session beans can belong to the @Dependent or @ApplicationScoped scopes,

  • Stateful session beans can belong to any scope

When using EJB in CDI you have the features of both specifications. You can for instance have asynchronous behavior and observer features in one bean.

But keep in mind that CDI implementation doesn’t hack EJB container, it only use it as any EJB client would do.

Thus, if you don’t use @Inject but @EJB to inject a session bean, you’ll obtain a plain EJB in your injection point and not a CDI session bean.

Bean types of a session bean

The set of bean types (used during typesafe resolution) for a given CDI session bean depend on its definition:

If the session has local interfaces, it contains:

  • all local interfaces of the bean,

  • all super interfaces of these local interfaces, and

  • Object class.

If the session bean has a no-interface view, it contains:

  • the bean class, and

  • evey superclass (including Object).

The set can also be restricted with @Typed.

Examples

@ConversationScoped
@Stateful
public class ShoppingCart { ... } (1)

@Stateless
@Named("loginAction")
public class LoginActionImpl implements LoginAction { ... } (2)


@ApplicationScoped
@Singleton (3)
@Startup (4)
public class bootBean {
 @Inject
 MyBean bean;
}
1 A stateful bean (with no-interface view) defined in @ConversationScoped scope. It has ShoppingCart and Object in its bean types.
2 A stateless bean in @Dependent scope with a view. Usable in EL with name loginAction. It has LoginAction in its bean types.
3 It’s javax.ejb.Singleton defining a singleton session bean.
4 The EJB will be instantiated at startup triggering instantiation of MyBean CDI bean.

Producers

Producers are the way to transform standard pojo into CDI bean.

A producer can only be declared in an existing bean through field or method definition.

By adding the @Produces annotation to a field or a non void method you declare a new producer and so a new Bean.

Field or method defining a producer may have any modifier or even be static.

Producers behave like standard managed bean:

  • they have qualifiers,

  • they have scope,

  • they can inject other beans: parameters in producer method are injection points that the container will satisfied when it will call the method to produce a contextual instance This injection points are still checked at deployment time.

Yet, producers have limitation compared to managed or session bean as they don’t support interceptors or decorators. You should keep this in mind when creating them as this limitation is not obvious when reading the spec.

If your producer (field or method) can take the null value you must put in in @Dependent scope.

Remember the Bean<T> interface we talked above ? You can see a producer method as a convenient way to define the Bean.create() method, even if it’s a bit more complicated.

So if we can define create() what about destroy()? It’s also available with disposers methods.

Disposers

A less known feature of producer is the possibility to define a matching disposer method.

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

Like producers, disposers methods must be define in a CDI bean, can have any modifier and even be static.

Unlike producer they should have one and only one parameter, called the disposer parameter and annotated with @Disposes. When the container container finds producer method or field, it looks for matching disposer method.

More than one producer can match to one disposer method.

Bean types of a producer

It depends of the type of the producer (field type or method returned type):

  • If it’s an interface, the bean type set will contain the interface all interface it extends (directly or indirectly) and Object.

  • If it’s a primitive or array type, the set will contain the type and Object.

  • If it’s a class, the set will contains the class, every superclass and all interface it implements (directly or indirectly).

Again, @Typed can restrict the bean types of the producer.

Examples

public class ProducerBean {

  @Produces
  @ApplicationScoped
  private List<Integer> mapInt = new ArrayList<>(); (1)

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

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

}
1 This producer field defines a bean with Bean types List<Integer>, Collection<Integer>, Iterable<Integer> and `Object
2 This producer method defines a EntityManager with @UserDatabase qualifier in @RequestScoped from an EntityManagerFactory bean produced elsewhere.
3 This disposer disposes all produced EntityManager (thanks to @Any qualifier)

Resources

Thanks to producer mechanism CDI allows to expose Java EE resources as CDI Bean.

These resources are:

  • persistence context (@PersistenceContext),

  • persistence unit (@PersistenceUnit),

  • remote EJB (@EJB),

  • web service (@WebServiceRef), and

  • generic Java EE resource (@Resource).

To declare a resource bean you only have to declare a producer field in a existing CDI bean

Declaring resources beans
@Produces
@WebServiceRef(lookup="java:app/service/PaymentService") (1)
PaymentService paymentService;

@Produces
@EJB(beanname="../their.jar#PaymentService") (2)
PaymentService paymentService;

@Produces
@CustomerDatabase
@PersistenceContext(unitName="CustomerDatabase") (3)
EntityManager customerDatabasePersistenceContext;

@Produces
@CustomerDatabase
@PersistenceUnit(unitName="CustomerDatabase") (4)
EntityManagerFactory customerDatabasePersistenceUnit;

@Produces
@CustomerDatabase
@Resource(lookup="java:global/env/jdbc/CustomerDatasource") (5)
Datasource customerDatabase;
1 producing a webservice from its JNDI name
2 producing a remote EJB from its bean name
3 producing a persistence context from a specific persistence unit with @CustomerDatabase qualifier
4 producing a a specific persistence unit with @CustomerDatabase qualifier
5 producing a Java EE resource from its JNDI name

Of course you can expose the resource in more complex way:

producing an EntityManager with COMMIT flush mode
public class EntityManagerBeanProducer {

  @PersistenceContext
  private EntityManager em;

  @Produces
  EntityManager produceCommitEm() {
    em.setFlushMode(COMMIT);
    return em;
  }
}

After declaration resources bean can be injected as any other bean.

Bean type of a resource

Resources exposed as bean with producer follow the same rules than producers regarding their type set.

Built-in beans

Beyond beans you can create or expose, CDI provides a lot of built-in beans helping you in your development

First the container should always provide built-in beans with @Default qualifier for the following interfaces:

  • BeanManager in @Dependent scope,to allow injection of BeanManager in an bean,

  • Conversation in @RequestScoped to allow management of the conversation scope.

To allow the use of events and programmatic lookup, the container must also provide built-in beans for with:

  • Event<X> in its set of bean types, for every Java type X that does not contain a type variable,

  • every event qualifier type in its set of qualifier types,

  • scope @Dependent,

  • no bean name.

For programmatic lookup the container must provide a built-in bean with:

  • Instance<X> and Provider<X> for every legal bean type X in its set of bean types,

  • every qualifier type in its set of qualifier types,

  • scope @Dependent,

  • no bean name.

A Java EE or embeddable EJB container must provide the following built-in beans, all of which have qualifier @Default:

  • a bean with bean type javax.transaction.UserTransaction, allowing injection of a reference to the JTA UserTransaction, and

  • a bean with bean type java.security.Principal, allowing injection of a Principal representing the current caller identity.

A servlet container must provide the following built-in beans, all of which have qualifier @Default:

  • a bean with bean type javax.servlet.http.HttpServletRequest, allowing injection of a reference to the HttpServletRequest

  • a bean with bean type javax.servlet.http.HttpSession, allowing injection of a reference to the HttpSession,

  • a bean with bean type javax.servlet.ServletContext, allowing injection of a reference to the `ServletContext

Finally to allow introspection of dependency injection and AOP, the container must also provide the built-in bean in @Dependent scope for the following interfaces when a an existing bean inject them:

  • InjectionPoint with @Default qualifier to get information about the injection point of a @Dependent bean,

  • Bean<T> with @Default qualifier to inject in a Bean having T in its typeset,

  • Bean<T> with @Intercepted or @Decorated qualifier to inject in an interceptor or decorator applied on Interceptor and Decorator for a bean having T in its typeset.

Check the spec on bean metadata to get all the restriction regarding Bean injection.

Custom beans

CDI gives you even more with Custom beans. Thanks to portable extension you can add your own kind bean allowing you to hook on the instantiation, injection and destruction of the instances.

You could for instance look in a registry to check for a given instance instead of instantiating the object.

I’ll show you on a coming post how to create such a bean in a portable extension.

Conclusion

As you see there are a lot of things happening behind the @Inject scene. Understanding them will help you to make a better use of CDI and give you a clearer entry point to Portable extension