Enterprise Java

Java EE CDI Producer methods tutorial

This is a tutorial of CDI Producer methods. In CDI, a Producer method generates an object that can then be injected. Producer methods can be used when we want to inject an object that is not itself a bean, when the concrete type of the object to be injected may vary at runtime, or when the object requires some custom initialization that the bean constructor does not perform. Producer methods allow us to expose any JDK class as a bean and define multiple beans, with different scopes or initialization, for the same implementation class. They also let us use runtime polymorphism with CDI.

Here we will create a simple service with two implementations and then we will create a Producer method to produce and inject both implementations in an application.

Our preferred development environment is Eclipse. We are using Eclipse Juno (4.2) version, along with Maven Integration plugin version 3.1.0. You can download Eclipse from here and Maven Plugin for Eclipse from here. The installation of Maven plugin for Eclipse is out of the scope of this tutorial and will not be discussed. Tomcat 7 is the application server used.

Let’s begin,

1. Create a new Maven project

Go to File -> Project ->Maven -> Maven Project.

New-Maven-Project

In the “Select project name and location” page of the wizard, make sure that “Create a simple project (skip archetype selection)” option is unchecked, hit “Next” to continue with default values.

new project

Here the maven archetype for creating a web application must be added. Click on “Add Archetype” and add the archetype. Set the “Archetype Group Id” variable to "org.apache.maven.archetypes", the “Archetype artifact Id” variable to "maven-archetype-webapp" and the “Archetype Version” to "1.0". Click on “OK” to continue.

maven-archetype-webapp

In the “Enter an artifact id” page of the wizard, you can define the name and main package of your project. Set the “Group Id” variable to "com.javacodegeeks.snippets.enterprise" and the “Artifact Id” variable to "cdibeans". The aforementioned selections compose the main project package as "com.javacodegeeks.snippets.enterprise.cdibeans" and the project name as "cdibeans". Set the “Package” variable to "war", so that a war file will be created to be deployed to tomcat server. Hit “Finish” to exit the wizard and to create your project.

newcdiproject1

The Maven project structure is shown below:

newcdiproject2

    It consists of the following folders:

  • /src/main/java folder, that contains source files for the dynamic content of the application,
  • /src/test/java folder contains all source files for unit tests,
  • /src/main/resources folder contains configurations files,
  • /target folder contains the compiled and packaged deliverables,
  • /src/main/resources/webapp/WEB-INF folder contains the deployment descriptors for the Web application ,
  • the pom.xml is the project object model (POM) file. The single file that contains all project related configuration.

2. Add all the necessary dependencies

You can add the dependencies in Maven’s pom.xml file, by editing it at the “Pom.xml” page of the POM editor, as shown below:
 
pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodegeeks.snippets.enterprise.cdi</groupId>
	<artifactId>cdibeans</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>cdibeans Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>org.jboss.weld.servlet</groupId>
			<artifactId>weld-servlet</artifactId>
			<version>1.1.10.Final</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.glassfish</groupId>
			<artifactId>javax.faces</artifactId>
			<version>2.1.7</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>cdibeans</finalName>
	</build>
</project>

As you can see Maven manages library dependencies declaratively. A local repository is created (by default under {user_home}/.m2 folder) and all required libraries are downloaded and placed there from public repositories. Furthermore intra – library dependencies are automatically resolved and manipulated.

3. Create a simple Service

The service that will be used in the Producer in this example is a simple service that creates a greeting message for the application that uses it. The GreetingCard.java class is an interface with a method that produces the greeting message.

GreetingCard.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

public interface GreetingCard {

	void sayHello();
}

The implementation of the service is shown below:

GreetingCardImpl.java

package com.javacodegeeks.snippets.enterprise.cdibeans.impl;

import com.javacodegeeks.snippets.enterprise.cdibeans.GreetingCard;

public class GreetingCardImpl implements GreetingCard {

	public void sayHello() {
		System.out.println("Hello!!!");
	}

}

In order to show how polymorphism works in CDI we will create another implementation of the service, as shown below:

AnotherGreetingCardImpl.java

package com.javacodegeeks.snippets.enterprise.cdibeans.impl;

import com.javacodegeeks.snippets.enterprise.cdibeans.GreetingCard;


public class AnotherGreetingCardImpl implements GreetingCard {

	public void sayHello() {
		System.out.println("Have a nice day!!!");
	}

}

4. Use of the Producer in a Managed Bean

In the managed bean below, we are making use of the Producer created above. In particular, in the GreetingCardFactory.java class, we create a method, getGreetingCard(), annotated with the @Produces annotation. The method returns the correct implementation of the GreetingCard according to the GreetingType of the bean. In this way the polymorphism is supported.

GreetingCardFactory.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;

import com.javacodegeeks.snippets.enterprise.cdibeans.impl.AnotherGreetingCardImpl;
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.GreetingCardImpl;

@SessionScoped
public class GreetingCardFactory implements Serializable {

	private static final long serialVersionUID = -44416514616012281L;

	private GreetingType greetingType;

	@Produces
	public GreetingCard getGreetingCard() {

		switch (greetingType) {
		case HELLO:
			return new GreetingCardImpl();
		case ANOTHER_HI:
			return new AnotherGreetingCardImpl();
		default:
			return new GreetingCardImpl();
		}
	}
}

The GreetingType.java is an enumeration, as shown below:

GreetingType.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

public enum GreetingType {

	HELLO, HI;
}

Another way to use polymorphism in CDI is through the @Qualifier. We can create our own annotation in CDI, and then use it to in the Producer method to get the correct implementation.

Greetings.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

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

	GreetingType value();

}

Now, the GreetingCardFactory can have a different Producer method for every implementation. The annotation we created is used after the @Produces annotation.

GreetingCardFactory.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;

import com.javacodegeeks.snippets.enterprise.cdibeans.impl.AnotherGreetingCardImpl;
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.GreetingCardImpl;


@SessionScoped
public class GreetingCardFactory implements Serializable {

	private static final long serialVersionUID = -44416514616012281L;

	private GreetingType greetingType;

	
	@Produces
	@Greetings(GreetingType.HELLO)
	public GreetingCard getGreetingCard() {
		return new GreetingCardImpl();
	}
	
	@Produces
	@Greetings(GreetingType.HI)
	public GreetingCard getAnotherGreetingCard() {
		return new AnotherGreetingCardImpl();
	}
	
}

5. Scope of Producer

An important thing to notice when creating a Producer method is the scope of the Producer. The scope of the Producer is set to Dependent by default. But a Producer may also have any other scope according to its use. The problem is, what may happen if a Producer produces a managed bean of a different scope. For example, we can create a @RequestScoped bean and inject it to another bean, using a Producer annotated as @SessionScoped. In this case, the instance of the @RequestScoped bean that the Producer returns will be destroyed after the HTTP request finishes and the behaviour of the bean where it is injected might be unexpected. In order to avoid having reference to no longer existing beans, we can make use of the @New annotation when using a Producer method. In this way, a new Dependent instance is injected via the Producer, as shown in the code snippet below:

GreetingCardFactory.java

package com.javacodegeeks.snippets.enterprise.cdibeans;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Produces;

import com.javacodegeeks.snippets.enterprise.cdibeans.impl.GreetingCardImpl;


@SessionScoped
public class GreetingCardFactory implements Serializable {

	private static final long serialVersionUID = -44416514616012281L;
	
	private GreetingCardImpl greetingCard;
	
	@Produces
	public GreetingCardImpl getGreetingCard(@New GreetingCardImpl greetingCard) {
		return greetingCard;
	}

	
}

6. Run the application

In order to run the application, we have created a simple servlet, as shown below:

GreetingServlet.java

package com.javacodegeeks.snippets.enterprise.cdibeans.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.javacodegeeks.snippets.enterprise.cdibeans.GreetingCard;
import com.javacodegeeks.snippets.enterprise.cdibeans.GreetingType;
import com.javacodegeeks.snippets.enterprise.cdibeans.Greetings;

@WebServlet(name = "greetingServlet", urlPatterns = {"/sayHello"})
public class GreetingServlet extends HttpServlet {

	private static final long serialVersionUID = 2280890757609124481L;
	
	@Inject
	@Greetings(GreetingType.HELLO)
	private GreetingCard greetingCard;

	@Inject
	@Greetings(GreetingType.HI)
	private GreetingCard anotherGreetingCard;

	  public void init() throws ServletException {
	  }

	  public void doGet(HttpServletRequest request, HttpServletResponse response)
	            throws ServletException, IOException {
	      response.setContentType("text/html");
	      PrintWriter out = response.getWriter();
	      out.println("<h1>" + greetingCard.sayHello() + "</h1>");
	      out.println("<h1>" + anotherGreetingCard.sayHello() + "</h1>");
	  }
	  
	  public void destroy(){
	  }

}

In the servlet above both implementations are injected. To run the example we must build the project with Maven, and then place the war file produced in webbaps folder of tomcat. Then, we can hit on :

http://localhost/8080/cdibeans/sayHello

and the result is the one shown below:

prod

 
This was a tutorial of Java EE CDI Producer methods.
 
Download the source code of this tutorial: CDIProducerMethodExample.zip

Theodora Fragkouli

Theodora has graduated from Computer Engineering and Informatics Department in the University of Patras. She also holds a Master degree in Economics from the National and Technical University of Athens. During her studies she has been involved with a large number of projects ranging from programming and software engineering to telecommunications, hardware design and analysis. She works as a junior Software Engineer in the telecommunications sector where she is mainly involved with projects based on Java and Big Data technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Alex
Alex
11 years ago

Hi Theodora, I enjoyed your article very much. Its well explained. However I have one question regarding the GreetingCardFactory.java (the first one) in point 4. How and when is the greetingType set? I can’t see that there is a setter method or that its value you is injected.

dh_teck
dh_teck
10 years ago

greatings
The value will be injected while deploying the project so the container is the manager of the life cycle of the instance an not the application because CDI is a container managed environement.

Java explore
Java explore
9 years ago

Hello,

This is awesome tutorial to read.

I have tried the sample but facing two issues .

1.Geeting below issues on the eclipse when using the first step.

Can’t resolve Archetype org.apache.maven.archetypes:maven-archetype-webapp:1.0
org.eclipse.core.runtime.CoreException: Could not resolve artifact

2. @Target({FIELD,TYPE, METHOD }) – The above annotations are not being compile on both 1.7 and 1.8 Jdk.

Please help

Kumar Anand
Kumar Anand
8 years ago

Hi!
Thanks for nice article.I have tried the sample and Now no doubt related to @produce.
But in GreetingCardFactory
for the following code,how will I set greetingType .
switch (greetingType) {
// case HELLO:
// return new GreetingCardImpl();
// case HI:
// return new AnotherGreetingCardImpl();
// default:
// return new GreetingCardImpl();
// }

Back to top button