Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Using Generics With Java Persistence and Tech Tips Quiz

 
In this issue
 
Welcome to the Enterprise Java Technologies Tech Tips for April 28, 2007. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

This issue covers:

These tips were developed using the NetBeans IDE and the Java EE 5 SDK. NetBeans IDE 5.5 with the NetBeans Enterprise Pack 5.5 is available in Java EE 5 SDK Update 2, which you can download from the Java EE Downloads page.

You can download the sample archive for the tip Using Generics With Java Persistence.

Any use of this code and/or information below is subject to the license terms.

 
Using Generics with Java Persistence
By Sean Brydon and Inderjeet Singh  

The Java Persistence API (or simply Java Persistence) provides a POJO-based domain model for Java EE 5 applications. It handles all of the details of how relational data is mapped to Java objects, and it standardizes object-relational mapping. Often applications that use Java Persistence execute queries that return a collection of objects. Java Platform, Standard Edition (Java SE) 5 introduced a new feature called generics that lets you specify the type of objects in collections. If you use Java Persistence in your applications, you can take advantage of generics to gain some extra benefits for your code such as type safety. In this tip you'll learn how to refactor applications to use generics.

A sample web application package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).

The Basics of Generics

Although not the only thing it's used for, generics gives you a way to communicate the type of objects in a collection. Using generics, you specify a collection with a parameter that represents a class. For example, the following declares that the method getAllItems returns a collection of objects of type Item:

   public List<Item> getAllItems(){...}

Using generics is a good practice for the following reasons:

  • It allows the compiler to do type checking and catch potential bugs in your code. If you don't use generics, you won't find those bugs until the application runs.
  • It can help identify bugs before deployment.
  • It can make your code more readable. When other developers read your code, they can see what type of objects are expected in a collection.
  • Without generics, the client code has to typecast each object it gets from a collection.

A Persistence Example

To illustrate using generics with Java Persistence, let's looks at a simple Java Persistence example. In this example a JSP page makes a request to find all the items in a database and show them in an XML document.

The request is processed as follows:

Java Persistence example

  • The main JSP page (index.jsp) sends the request to a servlet.
  • The servlet directs the request to a Facade.
  • The Facade creates a query using the Java Persistence Query Language to find all items in the database. The Facade could be a web component such as a servlet or a session bean.
  • The Java Persistence Runtime executes the query, does the object-relational mapping, builds a list of Items, and performs some other tasks.
  • The database executes an SQL query and returns a list of results, each of which represents one item (that is, one row) in the database.
  • The Facade passes the List to the servlet.
  • The servlet returns the List to the JSP page (itemsxml.jsp), which displays all the items as XML.

Let's start by looking at the Facade. Here is what the code for the request in the Facade looks like:

   public List getAllItemsInPlainCollection(){
      EntityManager em = emf.createEntityManager();
      Query query = em.createQuery(
             "SELECT OBJECT(i) FROM Item i");
      List items = query.getResultList();
      em.close();
      return items;
   }

To "generify" the code, all you have to do is make two additions to it as follows:

   public List<Item> getAllItemsInTypedCollection(){
      EntityManager em = emf.createEntityManager();
      Query query = em.createQuery(
             "SELECT OBJECT(i) FROM Item i");
      List<Itemgt; items = query.getResultList();
      em.close();
      return items;
   }

The changed code specifies that the return value will contain objects of type Item.

Now let's look at the pertinent code in the servlet:

   public void doGet(HttpServletRequest request, 
          HttpServletResponse response)
       ...
       if (selectedURL.equals("findallitems.do")) {
           List items = cf.getAllItems();
           request.setAttribute("items", items);
    }

Now the itemsxml.jsp page:

   ...
        <Items>
           <% List items = (List)request.getAttribute("items");
           for (Object o : items) {
           Item item = (Item) o; %>  
           <Item>
               <Name><%=item.getName()%> </Name>
               <ListPrice>$<%=item.getListPrice()%> </ListPrice>
               <Description><%=item.getDescription()%> 
               </Description>               
           </Item>            
           <% } %> 
        </Items>
   ...  

Notice how each item in the list of items must be cast to the proper type. By using generics, you can avoid the need for casting, as shown in the following code:

   ...  
       <Items>
           <% List<Item> items = (List<Item>)
                   request.getAttribute("items");
           for (Item item : items) { %>
           <Item>
               <Name><%= item.getName() %></Name>
               <ListPrice>$<%=item.getListPrice()%></ListPrice>
               <Description><%=item.getDescription()%>
               </Description>
           </Item>
           <% } %>
        </Items>
     ...

And finally, here is part of the code for the Item class, a simple persistence object. As mentioned previously, the query in this example returns a list of these Item objects, each of which represents a row in the database.

   import javax.persistence.*;
   @Entity       
   public class Item implements java.io.Serializable {   
      
       private int itemID;
       private String name;
       ...other fields listed here
      
       public Item() { }

      
       @Id
       public int getItemID() {
           return itemID;
       }   
       public String getName() {
           return name;
       }
      
       public void setItemID(int itemID) {
           this.itemID = itemID;
       }
       public void setName(String name) {
           this.name = name;
       }
       //...other getters and setters methods 
   }

Generics Collections are Not Polymorphic

When you use generics, you need to be aware that generics collections are not polymorphic. If you're new to generics, you might assume that you're allowed to assign an object of type List<Item> to an object reference of type List<Object>. Somewhat counter intuitively, this is not the case. For example, the following code produces a compile-time error:

   public List<Object> getAllItems() {
     // .... initialize the query object appropriately
     List<Item> results = query.getResultList();
     // the following return value will generate 
     // a compile-time error
     return query; 
   }

The code produces a compile-time error to protect the type integrity of the collection. Remember, the collection is supposed to be a list of Item objects only. If the code above was valid, you could add other types of objects, such as an Address object, to the collection through the add method of List<Object>.

One alternative and legal way of expressing the same intent is to use generics with wildcards. For example:

   public List<?> getAllItemsasObjects() {
     // .... initialize the query object appropriately
     List<Item> results = query.getResultList();
     return query;
   }   

Notice here that the return value is not a collection of arbitrary objects. It is a collection of unknown objects, where nothing can be assumed about their types. In fact, any method of Collections, such as the add method, that needs a specific type results in a compile time error. The only methods that can be used are those that assume the type to be java.lang.Object.

Preventing Spurious Warnings

Another thing to keep in mind is that the current version (1.0) of the Java Persistence API does not take advantage of generics to ensure better type safety. This can result in spurious warnings if your code uses generics. The following code elicits the problem:

   public List<Item> getAllItemsInTypedCollection(){
     EntityManager em = emf.createEntityManager();
     Query query = em.createQuery(
            "SELECT OBJECT(i) FROM Item i");
     List<Item> items = query.getResultList();
     em.close();
     return items;
   }

If you compile the code using the -Xlint:unchecked option it generates the warning:

   warning: [unchecked] unchecked conversion
   found : java.util.List
   required: 
     java.util.List<com.sun.javaee.blueprints.autoid.model.Item>
   List<Item> items = query.getResultList();

If you're not familiar with the -Xlint:unchecked option, it tells the compiler to give more detail for unchecked conversion warnings that are mandated by the Java Language Specification.

The warning is generated because query.getResultList() returns a non-generic version of List. However the items variable is of type List<Item>. This warning is spurious because the actual result of the query is a List of Item objects. Using a typecast of (List<Item>) does not solve the problem because the compiler does not preserve the generics type information for the runtime. In a future version of the Java Persistence API, the javax.persistence.Query class will likely change to better support generics. Until then, the best way to eliminate the spurious warning is to use the @SuppressWarnings annotation as shown in the following code example:

    @SuppressWarnings("unchecked")   
    public List<Item> getAllItemsInTypedCollection(){
      EntityManager em = emf.createEntityManager();
      Query query = em.createQuery(
           "SELECT OBJECT(i) FROM Item i");
      List<Item> items = query.getResultList();
      em.close();
      return items;
    }

For Further Information

For additional information about generics and the Java Persistence API, see:

Running the Sample Code

The sample code for this tip is available as a NetBeans project. You can build and run the sample code using the NetBeans IDE. You can also build and run the sample code from the command line. Instructions for building and running the sample code from the command line are in the README file in the sample package for the tip.

You can build and run the sample code using the NetBeans IDE as follows:

  1. If you haven't already done so, download and install the NetBeans IDE. NetBeans IDE 5.5 with the NetBeans Enterprise Pack 5.5 is available in Java EE 5 SDK Update 2, which you can download from the Java EE Downloads Page.

  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/bp-persistence-webonly, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\bp-persistence-webonly.

  3. Start the NetBeans IDE.

  4. Open the bp-persistence-webonly project. You'll be prompted to resolve the missing reference to javadb.root. Close the prompt message. Resolve the missing reference as follows:

    • Right click on the bp-persistence-webonly node in the Projects window.
    • Select "Resolve Reference Problems ...".
    • Click the Resolve ... button.
    • Browse to the javadb directory below the installation directory of Sun Application Server.
    • Click the Close button.

  5. Start the Java DB database as follows:

    • Select "Java DB Database" in the Tools menu.
    • Select "Start Java DB Server".

  6. Build the project as follows:

    • Right click the bp-persistence-webonly node in the Projects window.
    • Select "Clean and Build Project".

  7. Run the project as follows:

    • Right click the bp-persistence-webonly node in the Projects window.
    • Select "Run Project".

When you run the project (at URL http://localhost:8080/bp-persistence-webonly/) your browser should display the opening page of the Java Persistence Sample Application.

Java Persistence Sample Application

About the Authors

Sean Brydon is an engineer with Sun Microsystems where he is the technical lead for the Java BluePrints program. He has been involved with the Java BluePrints since its inception. He is an author of the Addison-Wesley Java-series books, "Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition," and "Designing Web Services with the J2EE 1.4 Platform." He is a regular speaker on enterprise application design. Sean has also been involved in designing and developing the Java Pet Store 2.0 reference application and the Java BluePrints Solutions Catalog.

Inderjeet Singh is a software engineer at Google, Inc. Prior to joining Google, Inderjeet spent 10 years at Sun Microsystems as a senior staff engineer where he was an architect for the Java EE SDK, Java Application Platform SDK, and the Java BluePrints program.

Tech Tips Quiz

Over the years, the Enterprise Java Technologies Tech Tips have covered a wide variety of enterprise Java technology topics. Here's a short quiz that tests your knowledge of some topics covered in past Tech Tips. You can find the answers at the end of the quiz.

  1. The following code snippet injects EntityManager instances into a JSF managed bean. The bean, BookBean, is an application-scoped JSF managed bean:

          public class BookBean {
              @PersistenceContext EntityManager em;
          ...
              public String placeOrder() {
          ...
                 em.persist(order);
          ...  
              }
          }

    What is the problem, if any, with this approach?
    1. You cannot inject EntityManager instances into JSF managed beans.
    2. EntityManager instances are not thread safe, so you should not inject them into JSF managed beans that have a scope of session or application.
    3. The approach does not conform to the MVC paradigm.
    4. You cannot specify a @PersistenceContext annotation on an EntityManager.

  2. Can jMaki widgets communicate with PHP?
    1. Yes.
    2. No.

  3. Which of the following WS-* security specifications does Web Services Interoperability Technology (WSIT) implement?
    1. WS-Security
    2. WS-SecurityPolicy
    3. WS-SecureConversation
    4. WS-Trust
    5. None of the above.
    6. All of the above.

  4. True or false, an important benefit of using the @EJB annotation with a 2.x home interface is that it frees you from having to use PortableRemoteObject.narrow()?
    1. True.
    2. False.

  5. What is a Model Facade?
    1. A proxy that acts as the model in an application that follows the MVC paradigm.
    2. A filter that preprocesses XML returned by a server in response to an Ajax request.
    3. A design pattern that defines a class for encapsulating and centralizing the interactions between Java Persistence clients and persistent entities.
    4. There is no such thing as a Model Facade.

Answers

  1. The following code snippet injects EntityManager instances into a JSF managed bean. The bean, BookBean, is an application-scoped JSF managed bean:

          public class BookBean {
              @PersistenceContext EntityManager em;
          ...
              public String placeOrder() {
          ...
                 em.persist(order);
          ...  
              }
          }

    What is the problem, if any, with this approach?

    1. EntityManager instances are not thread safe, so you should not inject them into JSF managed beans that have a scope of session or application. Here is a better approach. It uses the EntityManagerFactory to create EntityManager instances. It also uses a request-scoped JSF managed bean -- this helps ensure thread safety.

            public class BookBean {
                @PersistenceContext EntityManager em;
            ...
                public String placeOrder() {
            ...
                   em.persist(order);
            ...  
                }
            }

      For more information about Java Persistence and JSF, see the November 18, 2006 Tech Tip Using Java Persistence With JavaServer Faces Technology.

  2. Can jMaki widgets communicate with PHP?

    1. Yes. jMaki is a lightweight framework for creating Web 2.0 applications using standards-based technologies such as CSS, HTML, and JavaScript. It focuses on the aspects of delivering JavaScript to the client allowing the JavaScript to communicate with server-side technologies in a way that's neutral to the technology. The server-side technologies include PHP, JavaServer Pages (JSP) technology, JavaServer Faces technology, and Phobos. You can learn more about jMaki in the January 27, 2007 Tech Tip Introduction to jMaki.

  3. Which of the following WS-* security specifications does Web Services Interoperability Technology (WSIT) implement?

    1. All of the above. WSIT is an implementation of open web services technologies that enables interoperability between Java EE and .Net. WSIT addresses key aspects of web services interoperability such as reliable messaging, transaction handling, and security. WSIT implements a number of WS-* security specifications, including the ones listed in the question. You can learn more about WSIT in the March 31, 2007 Tech Tip Securing Web Services Using WSIT.

  4. True or false, an important benefit of using the @EJB annotation with a 2.x home interface is that it frees you from having to use PortableRemoteObject.narrow()?

    1. True. The PortableRemoteObject.narrow() method is used to cast to the correct type the Object returned when you lookup the home interface through JNDI. The @EJB annotation was introduced as part of the EJB 3.0 specification. However, it was designed to be used with the older-style EJB 2.x home view in addition to the EJB 3.0 business interface view. The home reference injected by an @EJB annotation can be used without any special casting. This is one example of how legacy applications can take advantage of the EJB 3.0 API. For more information, see the February 24, 2007 Tech Tip EJB 3.0 Compatibility and Migration.

  5. What is a Model Facade?

    1. A design pattern that defines a class for encapsulating and centralizing the interactions between Java Persistence clients and persistent entities. A Model Facade (or simply a "Facade") provides a single interface for operations on a set of entities. Using the Facade pattern can make the code in Java Persistence clients cleaner. For example, a web component that uses a Facade to access the model tier does not have to be aware of all the details of the APIs for each entity. For more information about Model Facades see the November 18, 2006 Tech Tip Using a Model Facade. Also see the February 24, 2007 Tech Tip Using an EJB Session Bean as a Model Facade.
Developers Assistance

Need programming advice on Java EE? Try Developer Expert Assistance

2007 JavaOne Conference Expands Focus

The JavaOne conference is expanding its focus, highlighting business management, Web 2.0, as well as open-source technologies and platforms that interoperate with and extend the core Java platform. Register today. Check the 2007 JavaOne Conference page for details

Fish for a Flat Screen TV

Blog about GlassFish for a chance to win a 52-inch LCD HD TV. The contest runs May 1-June 15, 2007. For more details, see the contest page after May 1.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.