|
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
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:
- 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:
- 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.
- 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.
- Start the NetBeans IDE.
- 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.
- Start the Java DB database as follows:
- Select "Java DB Database" in the Tools menu.
- Select "Start Java DB Server".
- Build the project as follows:
- Right click the bp-persistence-webonly node in the Projects
window.
- Select "Clean and Build Project".
- 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.
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.
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.
- 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?
- You cannot inject
EntityManager instances into JSF managed
beans.
EntityManager instances are not thread safe, so you should
not inject them into JSF managed beans that have a scope
of session or application.
- The approach does not conform to the MVC paradigm.
- You cannot specify a
@PersistenceContext annotation on an
EntityManager.
- Can jMaki widgets communicate with PHP?
- Yes.
- No.
- Which of the following WS-* security specifications does Web
Services Interoperability Technology (WSIT) implement?
- WS-Security
- WS-SecurityPolicy
- WS-SecureConversation
- WS-Trust
- None of the above.
- All of the above.
- 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()?
- True.
- False.
- What is a Model Facade?
- A proxy that acts as the model in an application that
follows the MVC paradigm.
- A filter that preprocesses XML returned by a server
in response to an Ajax request.
- A design pattern that defines a class for encapsulating
and centralizing the interactions between Java
Persistence clients and persistent entities.
- There is no such thing as a Model Facade.
Answers
- 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?
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.
- Can jMaki widgets communicate with PHP?
- 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.
- Which of the following WS-* security specifications does Web
Services Interoperability Technology (WSIT) implement?
- 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.
- 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()?
- 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.
- What is a Model Facade?
- 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.
|