Friday Oct 30, 2009
Friday Oct 30, 2009
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.
Figure 1. The UI for the Guess Number JSF 2.0 Application
|
Here is the code for the application's UI:
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:
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:
Notice especially the following highlighted annotations in the bean.
@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.
@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.@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.
@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:
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:
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:
Here are what the highlighted annotations in the bean do:
@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.@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:
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.
<GFv3_inst> is where you installed the GlassFish v3 Preview application server.
weld-guess.war file to the
<GFv3inst>/domains/domain1/autodeploy directory.
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.
Interesting. Thanks.
Posted by Davide Perini on November 03, 2009 at 11:39 AM PST #
Great post!
Thank you!
Posted by chanel j12 watch on November 09, 2009 at 12:39 AM PST #
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
Posted by Jan Groth on November 10, 2009 at 04:02 AM PST #
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?
Posted by David Letterman on November 18, 2009 at 09:04 AM PST #