X

Using CDI and Dependency Injection for Java in a JSF 2.0 Application

Guest Author

by Roger Kitain

This Tech Tip covers the intersection of three powerful technologies that are part of the Java EE 6 platform: JSR 299: Contexts and Dependency
Injection, JSR 330: Dependency Injection For Java, and JSR 314: JavaServer Faces 2.0.

JSR 299: Contexts and Dependency
Injection (CDI)
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 addition, CDI services allow Java EE components, including EJB session beans and
JavaServer Faces (JSF) managed beans to be injected and to interact in a loosely coupled way by firing
and observing events. Perhaps most significantly,
CDI unifies and simplifies the EJB and JSF programming models. It allows enterprise beans to act as managed beans in a JSF application.
Through its services, CDI brings transactional support to the web tier. This can make it a lot easier to access transactional
resources in web applications. For example, CDI services makes it a lot easier to build a Java EE web application that accesses
a database with persistence provided by the Java Persistence API.

JSR 330: Dependency Injection For Java
introduces a standard set of annotations that can be used for dependency injection. Dependency injection is a popular technique
in developing enterprise Java applications. Unfortunately, there has not been a standard approach for annotation-based dependency injection.
Dependency Injection For Java changes that by providing a standardized and extensible API for dependency injection.
The API comprises a set of annotations for use on injectable classes.

JavaServer Faces technology provides a server-side component framework that is designed to simplify the development of user
interfaces (UIs) for Java EE applications. The latest release of the technology,
JSR 314: JavaServer Faces 2.0, makes UI development for
Java EE applications even easier through support for annotations and the addition of new features such as Facelets and
composite components.

This Tech Tip illustrates the use of CDI and Dependency Injection for Java in a JSF 2.0 application.

An Example Application

Let's look at some key parts of a JSF 2.0 application that uses CDI and Dependency Injection for Java. You can find
the source code for the application in the sample application package that accompanies this tip.
See Running the Sample Code for instructions on how to install and run the application.

Figure 1 shows the UI for the application. The UI prompts a user to guess a number that the system has randomly selected.
The prompt is as follows: I am thinking of a number between min to max, where min and max
represent the minimum and maximum values allowable as a guess, respectively. The UI displays a text field for the user to enter the number,
a Guess button to submit the number, and a Reset button to restart the game. If the user enters a number that is lower than the correct number,
the UI responds with the message Higher! It also changes the min value in the prompt message to one more than the guessed number. If the user's entry
is too high, the UI responds with the message Lower! and changes the max value in the prompt message to one less than the guessed number. The system
sets a limit for the number of guesses, and with each incorrect guess, the UI displays
a message that tells the user how many guesses remain. The game ends when the user correctly guesses the number or when the user reaches
the limit of guesses.









The UI for the Guess Number JSF 2.0 Application
Figure 1. The UI for the Guess Number JSF 2.0 Application


 

Here is the code for the application's UI:



   1.  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2. <html xmlns="http://www.w3.org/1999/xhtml"
3. xmlns:ui="http://java.sun.com/jsf/facelets"
4. xmlns:h="http://java.sun.com/jsf/html"
5. xmlns:f="http://java.sun.com/jsf/core">
6. <h:head>
7. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
8. <title>JSF 2.0 Weld Example</title>
9. </h:head>
10. <h:body>
11. <h:form id="NumberGuessMain">
12. <h:panelGrid styleClass="title-panel">
13. <h:outputText value="Guess Number" styleClass="title-panel-text"/>
14. <h:outputText value="Powered By JavaServer Faces 2.0 and Weld" styleClass="title-panel-subtext"/>
15. </h:panelGrid>
16. <div style="color: black; font-size: 24px;">
17. I'm thinking of a number between <span style="color: blue">#{game.smallest}</span> and <span style="color: blue">#{game.biggest}</span>. You have <span style="color: blue">#{game.remainingGuesses}</span>guesses.
18. </div>
19. <h:panelGrid border="1" columns="5" style="font-size: 18px;">
20. Number:
21. <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"/>
22. <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/>
23. <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" />
24. <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}" style="color: red"/>
25. <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}" style="color: red"/>
26. </h:panelGrid>
27. <div style="color: red; font-size: 14px;">
28. <h:messages id="messages" globalOnly="false"/>
29. </div>
30. <h:outputStylesheet name="stylesheet.css" />
31. </h:form>
32. </h:body>
33. </html>




The code for the UI should look familiar to you if you develop applications with JSF. In fact, everything on the page is standard JSF 2.0 view markup.
Notice the highlighted expression language (EL) expressions. These expressions refer to a contextual bean instance
named game. A contextual bean instance is also known as a managed bean or simply a bean.

Actually, the concept of managed beans goes beyond CDI. Managed beans, which is introduced in Java EE 6, is designed to unify all of the various types
of beans in Java EE, including JSF managed beans, enterprise beans, and CDI beans. A managed bean is a Java class that is treated as
a managed component by the Java EE container. Optionally, you can give it a name in the same namespace as that used by EJB components.
A managed bean can also rely on a small number of container-provided services, mostly related to lifecycle management and resource injection.
Other Java EE technologies such as JSF, EJB, and CDI build on this basic definition of a managed bean by
adding services. So, for example, a JSF managed bean adds lifecycle scopes, an EJB session bean adds services such as support
for transactions, and a CDI bean adds services such as dependency injection.

Returning to the highlighted EL expressions in the code for the UI, the EL expressions bind to various bean
properties and methods, as follows:

  • The EL expressions in line 17, 24, and 25 bind to bean properties.
  • The EL expressions in line 21 bind to bean properties and to a bean validation method.
  • The EL expressions in lines 22 and 23 bind to bean action methods.

As you can see, in JSF 2.0, binding to a CDI bean is no different than binding to a typical JSF managed bean.

The Anatomy of a Simple Contextual Bean

As mentioned previously, beans can be bound to a lifecycle context, can be injected, and can interact with other beans in
a loosely coupled way by firing and observing events. In addition, a bean may be called directly from Java code,
or as you've seen in the UI for the example application, it may be invoked in an EL expression. This enables a JSF page
to directly access a bean.

Let's examine the game bean used in the application. Here is its source code:



   1. package weldguess;
2.
3. import java.io.Serializable;
4. import javax.annotation.PostConstruct;
5. import javax.enterprise.context.SessionScoped;
6. import javax.enterprise.inject.Instance;
7. import javax.inject.Inject;
8. import javax.inject.Named;
9. import javax.faces.application.FacesMessage;
10. import javax.faces.component.UIComponent;
11. import javax.faces.component.UIInput;
12. import javax.faces.context.FacesContext;
13.
14. @Named
15. @SessionScoped
16. public class Game implements Serializable {
17. private static final long serialVersionUID = 1L;
18.
19. private int number;
20. private int guess;
21. private int smallest;
22.
23. @MaxNumber @Inject
24. private int maxNumber;
25.
26. private int biggest;
27. private int remainingGuesses;
28.
29. @Random @Inject Instance<Integer> randomNumber;
30.
31. public Game() {
32. }
33.
34. public int getNumber() {
35. return number;
36. }
37.
38. public int getGuess() {
39. return guess;
40. }
41.
42. public void setGuess(int guess) {
43. this.guess = guess;
44. }
45.
46. public int getSmallest() {
47. return smallest;
48. }
49.
50. public int getBiggest() {
51. return biggest;
52. }
53.
54. public int getRemainingGuesses() {
55. return remainingGuesses;
56. }
57.
58. public String check() throws InterruptedException {
59. if (guess>number) {
60. biggest = guess - 1;
61. }
62. if (guess<number) {
63. smallest = guess + 1;
64. }
65. if (guess == number) {
66. FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
67. }
68. remainingGuesses--;
69. return null;
70. }
71.
72. @PostConstruct
73. public void reset() {
74. this.smallest = 0;
75. this.guess = 0;
76. this.remainingGuesses = 10;
77. this.biggest = maxNumber;
78. this.number = randomNumber.get();
79. }
80.
81. public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) {
82. if (remainingGuesses <= 0) {
83. FacesMessage message = new FacesMessage("No guesses left!");
84. context.addMessage(toValidate.getClientId(context), message);
85. ((UIInput)toValidate).setValid(false);
86. return;
87. }
88. int input = (Integer) value;
89. if (input < smallest || input > biggest) {
90. ((UIInput)toValidate).setValid(false);
91. FacesMessage message = new FacesMessage("Invalid guess");
92. context.addMessage(toValidate.getClientId(context), message);
93. }
94. }
95. }




Notice especially the following highlighted annotations in the bean.

  • The @Named annotation in Line 14. This 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, game.
    The annotation enables the application to reference the bean by that name using the EL expressions in the view.
  • The @SessionScoped annotation in Line 15. This is a CDI annotation that specifies a scope for the bean.
    All beans have a scope that determines the lifecycle of their instances and which instances of the beans are visible to instances
    of other beans. The @SessionScoped annotation declares that this bean is a session scoped bean, meaning that its
    lifecycle is the lifecycle of the session.
  • The @Inject annotation in Line 23 and line 29. This 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 line 23, the annotation
    identifies a dependency injection point for the maxNumber field. Line 23 also specifies a qualifier annotation,
    @MaxNumber, that identifies the implementation to inject. Qualifiers are strongly-typed keys that help distinguish
    different uses of objects of the same type. Later in this tip, you'll learn more about qualifiers. Defining
    @MaxNumber as a qualifier annotation enables the injection of the limit value for the maximum number of guesses.
    In line 29, the @Inject annotation identifies a dependency injection point for the randomNumber
    field. Line 29 also specifies a qualifier annotation, @Random, that identifies the implementation to inject.
    Defining @Random as a qualifier annotation enables the injection of a random number that the user needs to guess.
  • The @PostConstruct annotation in line 72. This annotation is defined in
    JSR 250, Common Annotations for the Java Platform. The
    annotation is used to identify a method that will perform initialization after a component is created. Here, the
    reset()method is marked with a @PostConstruct annotation. After the bean is created, the
    reset()method initializes a number of variables such as remainingGuesses, which tracks the remaining number
    of guesses; biggest, which holds the value for the maximum number of guesses; and number,
    which holds the randomly generated number that the user needs to guess.

Supporting Annotations

You've seen that the bean uses the @Random and @MaxNumber annotations as qualifier annotations.
Now let's see how those annotations are defined.

Here is the definition of the @Random annotation:



   1. package weldguess;
2.
3. import static java.lang.annotation.ElementType.FIELD;
4. import static java.lang.annotation.ElementType.METHOD;
5. import static java.lang.annotation.ElementType.PARAMETER;
6. import static java.lang.annotation.ElementType.TYPE;
7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
8. import java.lang.annotation.Documented;
9. import java.lang.annotation.Retention;
10. import javax.inject.Qualifier;
11.
12. @Target( { TYPE, METHOD, PARAMETER, FIELD })
13. @Retention(RUNTIME)
14. @Documented
15. @Qualifier
16. public @interface Random {
17. }




The @Qualifier annotation in line 15 is a Dependency Injection For Java annotation that is used
to identify an annotation as a qualifier annotation. A qualifier identifies a specific implementation of
a Java class or interface to be injected. In order to use a qualifier annotation, you first need to define its
type as a qualifier. You use the @Qualifier annotation to do that.
Defining @Random as a qualifier annotation enables a random number to be injected into the application.

The @Qualifier annotation is also used in the definition of the @MaxNumber annotation, as shown below:



   1. package weldguess;
2.
3. import static java.lang.annotation.ElementType.FIELD;
4. import static java.lang.annotation.ElementType.METHOD;
5. import static java.lang.annotation.ElementType.PARAMETER;
6. import static java.lang.annotation.ElementType.TYPE;
7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
8. import java.lang.annotation.Documented;
9. import java.lang.annotation.Retention;
10. import java.lang.annotation.Target;
11. import javax.inject.Qualifier;
12.
13. @Target( { TYPE, METHOD, PARAMETER, FIELD })
14. @Retention(RUNTIME)
15. @Documented
16. @Qualifier
17. public @interface MaxNumber {
18. }




The @Qualifier annotation in line 16 defines @MaxNumber as a qualifier annotation.
Defining @MaxNumber as a qualifier annotation enables the injection of the maximum number of allowed guesses
into the application.

The Utility Bean

There is one more important component of the application, a utility bean named Generator.
Here is what the Generator bean looks like:



   1. package weldguess;
2.
3. import java.io.Serializable;
4. import javax.enterprise.context.ApplicationScoped;
5. import javax.enterprise.inject.Produces;
6.
7. @ApplicationScoped
8. public class Generator implements Serializable {
9. private static final long serialVersionUID = -7213673465118041882L;
10. private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
11. private int maxNumber = 100;
12. java.util.Random getRandom() {
13. return random;
14. }
15. @Produces @Random int next() {
16. return getRandom().nextInt(maxNumber);
17. }
18. @Produces @MaxNumber int getMaxNumber() {
19. return maxNumber;
20. }
21. }




Here are what the highlighted annotations in the bean do:

  • The @ApplicationScoped annotation in line 7 is a CDI annotation that specifies a scope for the class. The annotation
    declares that an instance of the Generator class exists for the lifecycle of the application.
  • The @Produces annotation in line 15 and line 18 is a CDI annotation that is used to identify a method as a
    producer method. A producer method is called whenever another bean in the application needs an injected object. In line 15, the
    producer method is next(). The method is called by the Beans Manager when the Game
    bean needs to obtain an instance of the next random number. In line 18, the producer method is getMaxNumber(). The method
    is called by the Beans Manager when the Game bean needs to obtain the maximum number of allowed
    guesses — in this case, 100.

How the Components Work Together

Let's return to the UI discussed earlier. When a user responds to the prompt and clicks the Guess button, CDI technology goes into action.
The Java EE container automatically instantiates a contextual instance of the Game bean and the Generator bean.
After the Game bean is created, its reset() method is called to initialize a number of variables such as
biggest, which holds the value for the maximum number of guesses, and number, which holds the randomly generated number
that the user needs to guess.

The Game bean gets the maximum number of guesses from its maxNumber field. Recall that a dependency injection
point with the qualifier annotation, @MaxNumber, is specified for the maxNumber field. Recall too that
a producer method, getMaxNumber(), in the Generator bean is associated with the @MaxNumber
qualifier annotation.
As a result, when the Game bean accesses the @MaxNumber field, it calls the getMaxNumber()
method in the Generator bean. The getMaxNumber() method returns the value of the maxNumber
field, that is, 100.

The Game bean takes a similar route to provide a random number for the user to guess. The bean calls the
randomNumber.get() method as part of its post-construct initialization. Recall that a dependency injection point with the
qualifier annotation, @Random, is specified for the randomNumber field, and a producer method,
getRandom(), in the Generator bean is associated with the @Random qualifier annotation.
As a result, when the Game bean calls the randomNumber.get() method, it invokes the getRandom()
method in the Generator bean. The randomNumber.get() method uses the getRandom()
method of the java.util.Random class to generate a random number within the range 0 to 100.


Running the Sample Code

A sample application accompanies this tip. To run the sample application, do the following:


  1. If you haven't already done so, download a recent
    promoted build or
    nightly build of the GlassFish v3 Preview
    application server.
  2. Download the sample application package, weld-guess.zip
  3. Extract the contents of the sample application package. You should see the WAR file for the application,
    weld-guess.war, as well as folders for the application source code.
    The source code for the UI is in the web folder. The source code for the beans and annotations are in the
    src folder.
  4. Start the GlassFish v3 Preview application server by entering the following command:

       <GFv3_inst>/bin/asadmin start-domain





    where <GFv3_inst> is where you installed the GlassFish v3 Preview application server.
  5. Deploy the sample application by copying the weld-guess.war file to the
    <GFv3inst>/domains/domain1/autodeploy directory.
  6. Execute the application by opening a browser and accessing the URL http://localhost:8080/weld-guess

Further Reading

For more information, see the following resources:


About the Author

Roger Kitain is the JavaServer Faces co-specification lead. He has been extensively involved with server-side web technologies
and products since 1997. Roger started working on JavaServer Faces technology in 2001, as a member of the reference
implementation team. He has experience with Servlet and JSP technologies. Most recently, Roger has been involved with
the CDI specification and integration of CDI with the GlassFish container. Read Roger Kitain's
blog.

Join the discussion

Comments ( 8 )
  • Davide Perini Tuesday, November 3, 2009

    Interesting. Thanks.


  • chanel j12 watch Monday, November 9, 2009

    Great post!

    Thank you!


  • Jan Groth Tuesday, November 10, 2009

    Thanks for this great post.

    I'm just wondering which part the JSR 330 plays in the game. Se(e/a)ms to me as if your example doesn't rely on any JSR 300 functionality, or am I wrong?

    Cheers,

    Jan


  • David Letterman Wednesday, November 18, 2009

    It's not clear to me how the Generator is injected. Suppose I write another class named Generator2 with the same annotations as your existing Generator but different implementations, how would the web app know which generator to use?


  • Roger Kitain Thursday, December 10, 2009

    JSR 330 includes the @inject annotation to inject artifacts. This is used in the application.


  • Roger Kitain Thursday, December 10, 2009

    With respect to the comment about ambiguous producer methods (Generator). Please refer to Section 4.7 in this doc:

    http://docs.jboss.org/weld/reference/1.0.0/en-US/html_single/#d0e1297

    I could not immediately locate verbage in the 299 spec.


  • Remy Girodon Tuesday, December 15, 2009

    Excellent article, thank you !


  • Patrick Nelson Monday, October 11, 2010

    for windows 7 running glassfish v3.0.1, in the "Running the Sample Code" Step 5 from above: The dir should be <GFv3inst>/glassfish/domains/domain1/autodeploy


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.