How to create your first CDI bean

Learn how to create your very first CDI bean and provide alternate implementations to it in this tutorial by Abdalla Mahmoud, the author of Developing Middleware in Java EE 8.

Before getting started, you may want to check my book “5 Steps to an extraordinary career“, which will guide you to build your dream career as a software developer! Click here to check it out.

A CDI bean is an application component that encapsulates some business logic. Beans can be used either by Java code or by the unified EL (expression language used in JSP and JSF technologies). Beans’ life cycles are managed by the container and can be injected into other beans. All you need to do to define a bean is to write a POJO and declare it to be a CDI bean. To do so, there are two primary approaches:

  • Using annotations
  • Using the beans.xml file

Both ways should work; however, folks prefer using annotations over XML as it’s handy and included in the actual coding context. So, why is XML just over there? Well, that’s because annotations are relatively new in Java (released in Java 5). Till then, there was no other way in Java than XML to provide configuration information to your application server. And since then, it continued to be just another way of defining beans.

Moreover, if both are used together, XML will override annotations. Some developers and application administrators tend to perform temporary changes or hot-fixes sometimes by overriding hardcoded programmatic configuration values using external XML files. It’s worth mentioning that this approach is not a recommended way to deploy things into production.

In this tutorial, you’ll learn to use the annotations approach to create your first CDI bean and provide alternate implementations to it.

The first CDI bean

In this example, you’ll perform the following two steps:

  • Define a CDI bean
  • Inject and use the CDI bean

Start the first step by creating a new Java class with the name MyPojo, and then write the following code:

@Dependent
public class MyPojo
   public String getMessage() {
       return "Hello from MyPojo !";
   }
}

That’s all it takes to create your first CDI bean. As you may have noticed, the bean is nothing more than a plain old Java object, annotated with the @Dependent annotation. This annotation, called the dependent scope, declares that POJO is a CDI component. The dependent scope tells the CDI context to create a new instance whenever you request an injection to this bean.

It’s time to move forward to the next step: injecting the just created CDI bean into another component. Create a servlet named ExampleServlet and write the following code:

@WebServlet(urlPatterns = "/cdi-example-1")
public class ExampleServlet extends HttpServlet {

   @Inject
   private MyPojo myPojo;

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
           throws ServletException, IOException {
       resp.getOutputStream().println(myPojo.getMessage());
   }
}

You have used the @Inject annotation to obtain an instance to the MyPojo class. Now run the application, and visit the following URL: http://localhost:8080/EnterpriseApplication1-war/cdi-example-1.

You should see a page with the following text:

Hello from MyPojo !

Congratulations! You have just created and used your first CDI bean. That was pretty simple, wasn’t it? It’s time now to provide your newly created bean with alternate implementations and make it more robust.

Providing alternative implementations to your bean

One of the greatest features of CDI is that you can provide two or more different implementations to the same bean. This is very useful if you wish to do one of the following:

  • Handling client-specific business logic that is determined at runtime. For example, providing different payment mechanisms for a purchase transaction.
  • Supporting different versions for different deployment scenarios. For example, providing an implementation that handles taxes in the US, and another one for Europe.
  • Easier management for test-driven development. For example, you can provide a primary implementation for production, and another mocked one for testing.

To do this, you’ll first have to first rewrite your bean as an abstract element (abstract class or interface); only then will you be able to provide different implementations in alignment with fundamental OOP principles. Rewrite the bean to be an interface as follows:

public interface MyPojo {
   String getMessage();
}

Next, create an implementation class to the new interface:

@Dependent
public class MyPojoImp implements MyPojo{

   @Override
   public String getMessage() {
       return "Hello CDI 2.0 from MyPojoImp";
   }
}

Now, without any modifications to the servlet class, you can test re-run the code; it should give the following output:

Hello from MyPojoImp !

What happened at runtime? The container has received your request to inject a MyPojo instance. Since the container has detected your annotation over an interface instead of a class stuffed with an actual implementation, it has started looking for a concrete class that implements this interface. After this, the container detects the MyPojoImp class that satisfies this criterion, thereby instantiating and injecting it for you.

Now, comes the critical part, which is providing another implementation. For this, of course, you’ll need to create a new class that implements the MyPojo interface. Create a class called AnotherPojoImp as follows:

@Dependent
public class AnotherPojoImp implements MyPojo{

   @Override
   public String getMessage() {
       return "Hello CDI 2.0 from AnotherPojoImp";
   }
}

Seems simple, right? Nope. Check the servlet code again and look at it from the container’s perspective—how would the container determine which implementation to inject at runtime? If you try running it, you’ll end up with the following exception:

Ambiguous dependencies for type MyPojo with qualifiers @Default

Now, how do you deal with this ambiguity? There must be some way to specify which implementation should be used at runtime, don’t you think? Of course, there is! This is what the next section deals with.

Using qualifiers

A qualifier is a user-defined annotation used to specify the bean implementation version you wish to use at runtime. The idea of qualifiers is pretty simple; all you have to do is define a qualifier and annotate both the bean and the injection point with this qualifier. Create a new annotation with the following code:

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface AnotherImp {

}

As you can see, the qualifier is a custom-defined annotation, which is itself annotated with the @Qualifier annotation. @Qualifier tells the container that this annotation will act as a qualifier, while @Retention(RUNTIME) tells the JVM that this annotation should be available for reflection use at runtime. This way, the container can check for this annotation at runtime. @Target{TYPE, METHOD, FIELD, PARAMETER} tells the compiler that this annotation can be used on types, methods, fields, and parameters. Anyway, the @Qualifier annotation is the key annotation here.

Here’s a summary of the annotations:

Annotation Description
@Qualifier Tells CDI that this annotation is going to be used to distinguish between different implementations to the same interface.
@Retention(RUNTIME) Tells JVM that this annotation is intended to be used in runtime. Required for qualifiers.
@Target({TYPE, METHOD, FIELD, PARAMETER}) Tells JVM that this annotation can be used on the mentioned syntax elements.

Next, add the @AnotherImp annotation to AnotherPojoImp, as follows:

@Dependent
@AnotherImp
public class AnotherPojoImp implements MyPojo{

   @Override
   public String getMessage() {
       return "Hello from AnotherPojoImp";
   }
}

The annotation’s role here is to tell the container that this version of the class is called AnotherImp. You can now reference this version by modifying the servlet as follows:

@WebServlet(urlPatterns = "/cdi-example")
public class ExampleServlet extends HttpServlet {

   @Inject @AnotherImp
   private MyPojo myPojo;
   ...
}

Run the example, and you should see the following:

Hello from AnotherPojoImp

Nevertheless, how can you reference the original implementation, MyPojoImp? There are two options to do so:

  • Define another qualifier for MyPojoImp, like the earlier example
  • Use the default qualifier

The default qualifier, as the name suggests, is the default one for any CDI bean that has not been explicitly qualified. Although an explicit declaration for the default qualifier is considered redundant and useless, it’s possible to explicitly declare your CDI bean as a default one by using the @Default annotation. Check out the following revision to the MyPojoImp class:

@Default
@Dependent
public class MyPojoImp implements MyPojo{
   ...
}

Again, @Default is redundant, but you should consider its existence even if you have not explicitly declared it. Now, to reference the MyPojoImp from the servlet, rewrite it as follows:

@WebServlet(urlPatterns = "/cdi-example")
public class ExampleServlet extends HttpServlet {

   @Inject @Default
   private MyPojo myPojo;
   ...
}

This way, the original MyPojoImp implementation will be injected instead.

If you found this article helpful and want to learn more middleware development, you can explore Developing Middleware in Java EE 8. The book takes a hands-on approach to explain the design and implementation of professional enterprise middleware solutions using Java EE’s latest features. The book is a must-read for all enterprise architects, designers, and developers interested in learning how to build robust middleware solutions.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *