Context Dependency Injection with JBoss Weld

Contexts and Dependency Injection (CDI) (JSR 299) defines a set of services for the Java EE environment that makes applications much easier to develop. It provides an architecture that allows Java EE components such as servlets, enterprise beans, and JavaBeans to exist within the lifecycle of an application with well-defined scopes.

In short, CDI helps to bridge a known “gap” between the enterprise tier and the web tier. Until now, if you were to access your business logic from your JSF pages, the best strategy would be to access the JSF Managed Beans which in turn contacted the enterprise components.
jsf-ejb

With CDI the JSF page can access directly enterprise components bringing transactional support to the web tier.

jsf-cdi
How does the magic trick happens ? This can happen thanks to the definition of Managed beans.

Managed Beans are container-managed objects with minimal programming restrictions. They support a small set of basic services, such as resource injection, lifecycle callbacks and interceptors.

Discovery of Beans

Bean classes are deployed in bean archives. A bean archive has the bean discovery modes:

  • all: All types in the archive are considered for injection.
  • annotated: Only types with bean-defining annotations will be considered for injection.
  • none:Disable CDI.

A bean archive that does not contain beans.xml but contains one or more bean classes with a bean-defining annotation, or one or more session beans, is considered an implicit bean archive. A bean with a declared scope type is said to have a bean-defining annotation.

Here is a sample beans.xml file for Jakarta EE 9:

<beans version="3.0" bean-discovery-mode="all"
       xmlns="https://jakarta.ee/xml/ns/jakartaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"  bean-discovery-mode="all">>
 
</beans>

To learn more about the beans.xml file, check this article: How to configure beans.xml in CDI applications

A simple example

Let’s understand this better with a sample. We will create a demo application which uses a Facelet to access directly a Session Bean (See this Facelets tutorial for info about facelets)

This sample page collects input (bound to the EL expression #{user.name}) and has an action. The action invokes directly an EJB method:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">
 
 <h:body>
 <h:form>
 <h:outputText value="Enter your name:" />
 <h:inputText id="name" value="#{user.name}"/> 

 <h:commandButton id="action" value="Done" action="#{clock.action}"  /> 
 <h:messages/>
</h:form>  
 </h:body>
 </html>

This is the sample EJB:

package sample;

import javax.ejb.Stateless;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Date;

@Named
@Stateless
public class Clock {
 
 @Inject User user;
 
 public void action() {
 
 String message = user.getName() + " it is now " + new Date().toString();    
 FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message));
 }

}

The @Named annotation is a Dependency Injection For Java annotation that is used to associate a name with the bean. Because there is no name specified as an argument to the annotation, the name of the bean will be the name of the JavaBean with its first letter made lowercase, that is, clock. The annotation enables the application to reference the bean by that name using the EL expressions in the view.

The @Inject annotation in is a CDI annotation that is used to identify a dependency injection point, that is, a point at which a dependency on a Java class or interface can be injected. In this case, the annotation identifies a dependency injection point for the user field of the User class.

And here’s the User class:

package sample;

import java.io.Serializable;

import javax.enterprise.context.*;
import javax.inject.Named;


@Named
@SessionScoped
public class User  implements Serializable {
 private String name;

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }
}

Here also, the @Named annotation associate the User class with its name (lowercased).
What you should note is the @SessionScoped annotation declares that this bean is a session scoped bean, meaning that its lifecycle is the lifecycle of the session. (And as such, it needs to be Serializable to save its state).

Building the Project

In order to build the above example, you can use the dependency that contains a CDI API implementation. For example, to use the latest Jakarta CDI:

<dependency>
    <groupId>jakarta.enterprise</groupId>
    <artifactId>jakarta.enterprise.cdi-api</artifactId>
    <version>4.0.1</version>
</dependency>

Focus on the Injection Points

You can inject a bean at a field, method, or constructor using @Inject. The following code shows a how to inject an Interface using a field injection point:

public interface Greeting {
    public String hello(String name);
}
public class SimpleGreeting implements Greeting {
    public String hello(String name) {
    return "Hi" + name;
    }
}

In the following Session Bean, @Inject specifies the injection point, Greeting specifies what needs to be injected, and greeting is the variable that gets the injection.

@Stateless
public class GreetingService {
@Inject Greeting greeting;
    public String hello(String name) {
    return greeting.hello(name);
    }
}

As said, you can also inject a managed bean on methods as in this example:

Greeting greeting;
    @Inject
    public setGreeting(Greeting greeting) {
    this.greeting = greeting;
}

Finally, you can also include at most one Class constructor marked with @Inject:

Greeting greeting;
@Inject 
public SimpleGreeting(Greeting greeting) {
this.greeting = greeting;
}

With that in mind, here is the bean initialization sequence:

  1. Default constructor or the one annotated with @Inject
  2. All fields of the bean annotated with @Inject
  3. All methods of the bean annotated with @Inject (the call order is not portable, though)
  4. The @PostConstruct method, if any
Found the article helpful? if so please follow us on Socials