Monday, November 25, 2013

Getting Started with Contexts and Dependency Injection and JSF 2.x

Contributed by Andy Gibson
Content on this page applies to NetBeans IDE 7.2, 7.3 and 7.4
Contexts and Dependency Injection (CDI), specified by JSR-299, is an integral part of Java EE 6 and 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 such as 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.
This tutorial is based on the blog post by Andy Gibson, entitled Getting Started with JSF 2.0 and CDI in JEE 6. It demonstrates how you can use the IDE to set up a Java web project with support for JSF 2.0 and CDI. It continues by showing how to wire CDI managed beans with Facelets pages, and concludes with a brief example of CDI integration with EJB technology.
NetBeans IDE provides built-in support for Contexts and Dependency Injection, including the option of generating the beans.xml CDI configuration file upon project creation, editor and navigation support for annotations, as well as various wizards for creating commonly used CDI artifacts.

To complete this tutorial, you need the following software and resources.
Software or ResourceVersion Required
NetBeans IDE7.1, 7.2, 7.3, 7.4, Java EE bundle
Java Development Kit (JDK)version 6 or 7
GlassFish serverOpen Source Edition 3.x or 4.x
Notes:
  • The NetBeans IDE Java bundle also includes the GlassFish Server Open Source Edition, which is a Java EE-compliant container.

Creating a Java Web Project with CDI Support

In this exercise you create a JSF 2.x-enabled Java web project with CDI support.
  1. Click the New Project ( New Project button ) button in the IDE's main toolbar (Ctrl-Shift-N; ⌘-Shift-N on Mac).
  2. In the New Project wizard, select the Java Web category, then select Web Application. Click Next.
  3. Type cdiDemo for the project name and set the project location. Click Next.
  4. Set the server to GlassFish server.
  5. Set the Java EE Version to Java EE 6 Web or Java EE 7 Web.
    Note. The Java EE version that you select determines the CDI version that is enabled for your application and there are some important differences between CDI 1.0 and CDI 1.1.
    • If you specify Java EE 6 Web as the Java EE version, confirm that the 'Enable Contexts and Dependency Injection' option is selected. The 'Enable Contexts and Dependency Injection' option, when selected, generates a beans.xml file in the project's WEB-INF folder when the project template is created. Thebeans.xml file is used by CDI to instruct the Java EE-compliant server that the project is a module containing CDI beans. Java EE 6 Web supports CDI 1.0 and the generated beans.xml file specifies CDI 1.0 as the version.
    • If you specify Java EE 7 Web as the Java EE version, CDI 1.1 is enabled by default and the beans.xml file is not required. In Java EE 7, when nobeans.xml is present the archive that is deployed is an implicit bean archive. If you use the New File wizard in the IDE to manually generate a beans.xmlfile in a Java EE 7 Web application, by default the deployed archive will become an explicit bean archive because the beans.xml file specifies CDI 1.1 as the version and also sets the attribute of the bean-discovery-mode to all.
    For more details on the types of CDI archives, see Packaging CDI Applications in the Java EE 7 Tutorial.
    Enable CDI option provided in New Web Application wizard
  6. Click Next.
  7. In the Frameworks panel, select the JavaServer Faces option.
  8. Click the Configuration tab and confirm that Facelets is selected as the Preferred Page Language. Click Finish.
    When you click Finish, the IDE generates the web application project and opens the index.xhtml welcome page in the editor.
  9. In the Projects window, expand the Libraries > GlassFish Server node you can see that the weld-osgi-bundle.jar library was automatically added. The GlassFish Server includes Weld, which is JBoss' implementation of the JSR-299 CDI specification.
    New project displayed in Projects window
    If you specified Java EE 6 Web as the Java EE version when you created the project, note that the Web Pages > WEB-INF folder includes a beans.xml file. This file is currently empty, but can be used to specify bean related information in XML as an alternative to annotations.

Accessing Beans from JSF's Expression Language

This exercise demonstrates how you can wire CDI managed beans to Facelets pages using EL syntax.
  1. In the Projects window, right-click the Source Packages node and choose New > Java Class.
  2. In the New Java Class wizard, name the class MessageServerBean, and type in exercise1 as the Package. (The new package is created upon completing the wizard.) Click Finish.
    New Java Class wizard
    The new package and class are generated, and the class opens in the editor.
  3. Annotate the class with the @Named and @Dependent annotations, and create a single method to return a string.
    package exercise1;
    
    import javax.enterprise.context.Dependent;
    import javax.inject.Named;
    
    @Dependent
    @Named
    public class MessageServerBean {
    
        public String getMessage() {
            return "Hello World!";
        }
    }
    As you type the @Dependent and @Named annotation, press Ctrl-Space to invoke the editor's code completion support, as well as Javadoc documentation. If you apply the annotation using the editor's code completion facilities (i.e., select the appropriate annotation and press Enter), the import statement is automatically added to the file. In the Javadoc pop-up, you can also click the 'Show documentation in external web browser' ( Show documentation in external web browser button ) button to display the full-sized Javadoc in a separate window.
    Note. The @Dependent annotation defines the scope of the managed bean. In an implicit bean archive a managed bean is only discoverable and can only be managed by the container when a scope is specified. The application in this tutorial will be packaged as an implicit bean archive if you specified Java EE 7 Web as the Java EE version when you created the project and you did not create beans.xml. For details on specifying the scope of managed beans, see Using Annotations to Configure Managed Beans in the Java EE 7 Tutorial.
  4. Save the file (Ctrl-S; ⌘-S on Mac). By adding the @Named annotation, the MessageServerBean class becomes a managed bean, as defined by CDI.
  5. Switch to the index.xhtml Facelets page (press Ctrl-Tab) in the editor, and add the following content to the  tags.
    
        Hello from Facelets
        
    
        Message is: #{messageServerBean.message}
        
    
        Message Server Bean is: #{messageServerBean}
    
    You can press Ctrl-Space in EL expressions to take advantage of code completion suggestions. The editor's code completion lists managed beans and their properties. Because the @Named annotation transforms the MessageServerBean class into a CDI managed bean, it becomes accessible within EL syntax, just as though it were a JSF managed bean.
    New Java Class wizard
  6. Click the Run Project ( Run Project button ) button in the IDE's main toolbar. The project is compiled and deployed to GlassFish, and the application welcome page (index.xhtml) opens in the browser. You can see the "Hello World!" message from the MessageServerBean displayed on the page.
    Welcome page displayed in browser
  7. Go back into the message bean and change the message to something else (e.g., "Hello Weld!"). Save the file (Ctrl-S; ⌘-S on Mac), then refresh the browser. The new message automatically appears. Thanks to the IDE's Deploy on Save feature, any changes you save result in automatic compilation and redeployment to the server.

    From the third line in the page you can see that the class name is exercise1.MessageServerBean. Note that the bean is just a POJO (Plain Old Java Object). Even though you are developing in Java EE, there is no complex class hierarchy wrapped in layers of transactions, interceptors and all that "heavy" stuff you keep hearing about.

What's Going On?

When the application is deployed the server looks for CDI managed beans. In a Java EE 7 application, the classes on the path are scanned for CDI annotations by default. In a Java EE 6 application, the classes are scanned for CDI annotations if the module contains a beans.xml file. In a CDI module, all beans are registered with Weld, and the @Named annotation is used to match beans to injection points. When the index.xhtml page was rendered, JSF tried to resolve the value of messageServerBeanin the page using the registered expression resolvers in JSF. One of these is the Weld EL Resolver which has the MessageServerBean class registered under the name messageServerBean. We could have specified a different name with the @Named annotation, but since we did not it was registered under the default name, being the class name with a lower-case first letter. The Weld resolver returns an instance of this bean in response to the request from JSF. Bean naming is only needed when using EL expressions and should not be used as a mechanism for injection since CDI provides type-safe injection by class type and qualifier annotations.

Upgrading to an EJB

As we are using a Java EE stack, we can easily deploy our bean as an EJB with some small changes thanks to EJB 3.1.
  1. Open the MessageServerBean and add the javax.ejb.Stateless annotation at the class level and change the string to 'Hello EJB!'.
    package exercise1;
    
    import javax.ejb.Stateless;
    import javax.enterprise.context.Dependent;
    import javax.inject.Named;
    
    /**
     *
     * @author nbuser
     */
    @Dependent
    @Named
    @Stateless
    public class MessageServerBean {
    
        public String getMessage() {
            return "Hello EJB!";
        }
    }
  2. Save the file (Ctrl-S; ⌘-S on Mac), then go to your browser and refresh. You will see output similar to the following:
    EJB details displayed in browser
    Amazingly, we turned our POJO into a fully-featured EJB with just one annotation. We saved changes then refreshed the page, and our changes appeared. In doing so it wasn't necessary to create any weird project configurations, local interfaces or arcane deployment descriptors.

Different EJB types

You can also try using the @Stateful annotation. Alternatively, you could try the new @Singleton annotation for singleton instances. If you do, you may notice that there is are two annotations: javax.ejb.Singleton and javax.inject.Singleton. Why two singletons? The CDI singleton (javax.inject.Singleton) lets you define a singleton instance outside of EJB in case you are using CDI in a non-EJB environment. The EJB singleton (javax.ejb.Singleton) provides all the features of an EJB such as transaction management. Therefore, you have the choice depending on your needs and whether you are working in an EJB environment.

See Also

The next installment of this series focuses on CDI injection, and provides a closer look at using CDI for managing dependencies in a Java EE environment.
For more information about CDI and JSF 2.0, see the following resources.