Technical Article

Web Tier to Go With Java EE 5: A Look at Resource Injection

By Ryan Lubke , June 2006

The focus of the Java Platform, Enterprise Edition (Java EE) 5 is ease of development, with the goal of making typical application tasks simpler. An important new feature that helps fulfill this goal is support for annotations. Annotations enable injecting dependencies, resources, services, and life-cycle notifications into a Java EE 5 platform application.

This fourth article of the series describes how the platform's web-tier technologies support injection through Java technology annotations to simplify access to resources, environment data, and life-cycle control.

A Look at Resource Injection

To understand how resource injection makes life easier for developers, let's look at how applications accessed resources prior to support for resource injection and how the Java EE 5 platform has simplified this access. In the past, accessing data sources, web services, environment entries, and EJB software references required the use of boilerplate code. For example, the code required to access the container-managed data source javax.sql.DataSource would look like this:



public javax.sql.DataSource getCatalogDS() {
                  

    try {
                  

        // Obtain the initial Java Naming and Directory Interface
                  

        // (JNDI) context.
                  

        InitialContext initCtx = new InitialContext();
                  

        // Perform JNDI lookup to obtain the resource.
                  

        catalogDS = (DataSource)
                  

            initCtx.lookup("java:comp/env/jdbc/catalogDS");
                  

    } catch (NamingException ex) {
                  

        // Handle failure.
                  

    }
                  

}
                  
...
                  

public getProductsByCategory() {
                  

    // Get the DataSource.
                  

    DataSource catalogDS = getCatalogDS();
                  

    // Get a connection and execute the query.
                  

    Connection conn = catalogDS.getConnection();
                  
    ...                

}
             
         

In order to look up a data source, a developer had to deal with the following:

  • Java Naming and Directory Interface (JNDI) API. The application looked up the resource by way of the JNDI API.
  • Casting. The look-up result had to be cast to the correct type.
  • Exception handling. The software had to handle the exceptions exposed by the JNDI API.

Moreover, the developer had to define the resource to acess in the deployment descriptor, web.xml, associated with the web application:



<resource-ref>
                  

    <description>Catalog DataSource</description>
                  

    <res-ref-name>jdbc/catalogDS</res-ref-name>
                  

    <res-type>javax.sql.DataSource</res-type>
                  

    <res-auth>Container</res-auth>
                  

</resource-ref>
            
        

The Java EE 5 platform defines annotations to support a variety of injections. We can now reduce the code in the example above to the following:



private @Resource DataSource catalogDS;
    
public getProductsByCategory() {
                  

    // Get a connection and execute the query.
                  

    Connection conn = catalogDS.getConnection();
                  
    ...
                  
} 
     
 

Because of the @Resource annotation, the developer does not need to worry about the boilerplate code that is normally required to get access to the resource. The catalogDS field of the javax.sql.DataSource type is annotated with @Resource and injected by the container prior to the component -- for example, a Servlet -- being made available to the application. The data source JNDI mapping is inferred from the catalogDS field name and javax.sql.DataSource type. Moreover, the catalogDS resource no longer needs to be defined in the deployment descriptor. Slick!

What Can Be Injected?

The support for injection is pervasive throughout the Java EE 5 platform. Many Java Community Process (JCP) program specifications have collaborated to define the various types of injections that the platform supports.

Chapter 5 of JSR 244, the Java platform specification, describes how applications declare dependencies on external resources and configuration parameters, how those items are represented in the Java EE 5 platform naming system, and how they can be injected into application components. This chapter puts in perspective everything related to the platform's resource access.

Further, Section 14.5 of the Servlet specification discusses the injection annotations that are supported in the Java EE 5 platform's web technologies. Table 1 lists the supported annotations.

Table 1: Annotations and Their Uses

Type of Annotation Annotation Name Action or Definition
Common annotations 1 @Resource Declares a reference to a resource such as a data source, Java Messaging Service (JMS) destination, or environment entry. This annotation is equivalent to declaring a resource-ref, message-destination-ref, env-ref, or resource-env-ref element in the deployment descriptor.
@Resources A collection of sorts to allow the declaration of multiple @Resource annotations.
@DeclaresRoles Specifies security roles that the application uses.
@RunAs Specifies the application's role during execution within a Java EE technology environment. Within the scope of the web tier, this annotation can be declared only on a Servlet and is the equivalent of declaring a run-as element on a Servlet in the deployment descriptor.
@PostConstruct Specifies a method that the container will invoke after resource injection is complete but before any of the component's life-cycle methods are called.
@PreDestroy Specifies a method that the container will invoke before removing the component from service.
EJB beans 2 @PersistenceContext Specifies the container-managed entity context.
@PersistenceContexts A collection of sorts to allow the declaration of multiple @PersistenceContext annotations.
@PersistenceUnit Specifies a reference to an entity manager factory for use with EJB beans specified in a component.
@PersistenceUnits A collection of sorts to allow the declaration of multiple @PersistenceUnit annotations.
Web services 3 @WebServiceRef Specifies a reference to a web service within a web component.
@WebServicesRefs A collection of sorts to allow the declaration of multiple @WebServiceRef annotations.

1 Common annotations: JSR 250, Common Annotations for the Java Platform Specification, provides the semantics of the platform's common annotations.

2 EJB beans: See JSR 220, the Enterprise JavaBeans 3.0 Specification, Section 8.1, Annotation of Context Dependencies.

3 Web services: See JSR 224, the Java API for XML-Based Web Services (JAX-WS) 2.0 Specification, Section 7.9, javax.xml.ws.WebServiceRef.

What Components Can Accept Resource Injections?

Keep in mind that a Java EE 5 platform container can handle the injections transparently only when they are used on container-managed components, such as EJB beans, Servlets, and JavaServer Pages (JSP) technology tag handlers.

This is for two reasons. First, for performance considerations, a container can restrict its search of annotations only to the components it manages, which are defined in a deployment descriptor or are accessible in specific classpath locations. Second, the container must have control over the creation of the component to be able to transparently perform the injection into the component.

Although resource injection would be most useful in the web tier if it were applicable to any Plain Old Java Object (POJO), this will have to wait for a future release. Table 2 lists the web-tier-managed components that support resource injection in applications based on the Java EE 5 platform.

Table 2: Components That Support Resource Injection

Name Interface or Class
Servlets javax.servlet.Servlet
Servlet filters javax.servlet.ServletFilter
Event listeners

javax.servlet.ServletContextListener

javax.servlet.ServletContextAttributeListener

javax.servlet.ServletRequestListener

javax.servlet.ServletRequestAttributeListener

javax.servlet.http.HttpSessionListener

javax.servlet.http.HttpSessionAttributeListener

Taglib tag handlers javax.servlet.jsp.tagext.JspTag
JavaServer Faces technology-managed beans Plain Old Java Objects (POJOs)

JSP technology pages and tag files cannot accept resource injections either.  Because such pages are usually compiled only after receiving a request, an annotation included in a JSP technology page would not be available to the container at deployment time when resource injection occurs.

Tag library validators (TLVs) and TagExtraInfo (TEI) are other classes that the JSP technology container manages, but because their life cycle is limited to the compilation of the JSP technology pages, they are not valid candidates for injection.

Supporting resource injection on JavaServer Faces technology renderers, converters, or validators is not desirable because that would violate Model-View-Controller (MVC) separation of these presentation objects. If these classes need to get access to resources, they should do so through a managed bean.

Sample Code

A Simple Servlet

The classic first Servlet can now do more than just display the usual Hello World! message. It can easily display an entry from its Java EE 5 platform environment.




private @Resource String welcomeMessage;
                  
public class HelloWorld extends HttpServlet {
                  

    public void doGet(HttpServletRequest request, HttpServletResponse response)
                  
        throws ServletException, IOException {
                  
        PrintWriter out = response.getWriter();
                  
        out.println(welcomeMessage);
                  

}
                  
<env-entry>
                  

    <env-entry-name>welcomeMessage</env-entry-name>
                  

    <env-entry-type>java.lang.String</env-entry-name>
                  

    <env-entry-value>Hello World from env-entry!</env-entry-value>
                  

</env-entry>


  

A JavaServer Faces Technology-Managed Bean

The following example demonstrates the use of the @Resource annotation along with the life-cycle annotations @PostConstruct and @PreDestroy to simulate, in a simplified way, an EJB bean.

The managed bean has access to a DataSource object through the presence of the @Resource annotation. Next, it uses that DataSource to initialize itself with the annotated initBean() method before the managed bean is put into scope. The managed bean then uses the DataSource once again in the annotated flush() method to flush the data back to the database when the bean is removed from scope, that is, when the user has logged or timed out.



private @Resource javax.sql.DataSource userDS ;
                  
public class UserDataBean {
                  

    // Ivars pertaining to the user
                  

    @PostConstruct
                  

   public void initBean() {
                  

     Connection conn = userDS.getConnection();
                  

     // Use the connection to populate UserDataBean ivars.
                  

   }
                  

     @PreDestroy
                  

   public void flush() {
                  

     Connection conn = userDS.getConnection();
                  

     // Use the connection to flush any modified ivars
                  

     // to the back end.
                  

   }
                  
}
                                   

<managed-bean>
                  

  <managed-bean-name>userdata</managed-bean-name>
                  

  <managed-bean-class>somepkg.UserDataBean</managed-bean-class>
                  

  <managed-bean-scope>session</managed-bean-scope>
                  

<managed-bean>
            
        

Conclusion

As this article demonstrates, the support for resource injection in the web tier makes accessing resources from web applications significantly easier. Try it out. You'll probably be pleased with the amount of time and the number of lines of code you save. Meanwhile, watch for the next article in the "Web Tier to Go With Java EE 5" series, which will describe the new pound syntax introduced in the Unified Expression Language (UEL).

For More Information

About the Author

Ryan Lubke is a member of the team that develops Sun's implementation of the JavaServer Faces technology.