Guidelines, Tips, and Tricks for the Java EE 5 Platform
By Rick Palkovic
If you've been programming with some of the features recently
introduced into the Java Platform, Enterprise Edition 5 (Java EE 5),
such as annotations and generics, you'll be interested in session
TS-4593, "Guidelines, Tips, and Tricks for Using Java EE 5 From Java
BluePrints," presented Wednesday at 1:30 p.m. Speakers Inderjeet
Singh, Marina Vatkina, Mahesh Kannan, and Roger Kitain presented most
of the information in the form of code-example puzzles.
Kitain opened the session, presenting tips for programming in the web
tier. Tips included ways to simplify web deployment descriptor entries
by using wildcards in servlet names with filter-mapping descriptors.
He then presented some JavaServer Faces technology code that often
trips up novice developers.
Kannan followed, leading attendees through the intricacies of EJB
technology coding such as dependency injection in the Java EE 5
platform. He explained how the @Resource annotation
declares an environment dependency in addition to injecting that
dependency into the named variable. He then described ways to use EJB
3.0 interceptors to intercept business and life-cycle methods.
Next, Vatkina described issues that can trap unwary programmers in
the Java Persistence API. She explained how easy it is to write
deployment descriptor entries and package applications for using Java
persistence in Java EE and Java SE platform environments.
Finally, Singh provided other tips, such as how to use thread-safe
variants of annotations and how to use generics with the Java
Persistence API for better type safety. The following are some
examples from Singh's presentation.
Java EE annotations have been designed to work with thread-safe code.
For this very reason, Singh cautioned his audience to consider thread
safety when using annotations in the web tier. Some annotations
simply do not work because the web-tier model itself is not thread
safe.
Thread Safety and Annotations: Example 1
To drive home his point, Singh presented the following code fragment,
which uses the @PersistenceContext annotation:
public class MyServlet extends HttpServlet {
@PersistenceContext (unitName="CatalogPU")
private EntityManager em;
@Resource UserTransaction utx;
// ......
}
This use of the annotation @PersistenceContext in a
servlet is not thread safe, nor would it be safe in a JavaServer
Faces managed bean unless the bean is request-scoped. The use of
@Resource, however, is thread safe.
Singh summarized four ways to make the code thread-safe:
Use a request-scoped bean in a JavaServer Faces managed bean.
Use class-level annotations with Java Naming and Directory Interface (JNDI) lookups.
Use other annotations, such as @Resource.
Use old-fashioned JNDI lookups.
Singh presented the following example of a thread-safe alternative.
In this example, the @PersistenceContext annotation
declares only the deployment descriptor entry, so it is class-scoped.
Further, the servlet is thread safe because there is only one
JNDI lookup per method call.
@PersistenceContext(name="EM" unitName = "CatalogPU")
public class MyServlet extends HttpServlet {
public EntityManager getEntityManager() {
Context ic = new InitialContext();
return (EntityManager) ic.lookup("java:comp/env/EM");
}
Another thread-safe alternative is to use a different annotation, as
in the following example. In this example, the @PersistenceUnit
annotation injects EntityManagerFactory, which is a thread-safe
object. The servlet is thread safe because the method creates a new
entity manager for each call.
public class MyServlet extends HttpServlet {
@PersistenceUnit (unitName="CatalogPu")
private EntityManagerFactory emf;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
Thread Safety and Annotations: Example 2
Singh presented another example of code that looks correct but that
in fact can produce bugs that are difficult to characterize and fix.
At first glance, this code looks typical enough. However, it is not
guaranteed to work because of the way the servlet model is designed
-- nothing in the model requires that the filter's doFilter()
method and the servlet's service() method run in the
same thread. If they run in different threads, the user transaction
will fail, because transactions are not allowed to span threads. In
practice, the methods usually run in the same thread, and the code
works fine. But when the methods run in different threads, the
resulting failure can be difficult to track down.
A movement is afoot to make unsafe annotations a compile-time error.
Until then, unsafe annotations can pass unnoticed until they surface
as mysterious failures at runtime.
Java EE 5 applications create domain models using the Java
Persistence API. Often, these applications execute queries that
return a collection of objects. The generics feature lets you specify
the types of objects in collections.
Generics provide a way for you to communicate the type of the objects
in a collection to the compiler. When the compiler knows the
collection's element type, the compiler can check that you have used
the collection consistently and can insert the correct casts on
values being taken out of the collection.
When you build an application using the Java Persistence API, you can
leverage generics for type safety. Using generics is generally
regarded as good practice.
But using generics with Java persistence can be tricky. For example,
consider the following code fragment, which uses the Java Persistence
API to create a query:
public interface Query() {
public List getResultList();
}
Java persistence does not provide a generic version of the returned
collection. However, in most cases, you know the type of the objects
in the resulting collection, so you can use generics to build a
type-safe collection for subsequent use, as in the following example.
Query q = em.createQuery("SELECT OBJECT(i) FROM Item i");
List items = q.getResultList();
List> items3 = items;
In the example, the variable items is a genericized list
of Item objects. The variable items3 is
also a genericized list, but the type of the objects in the list is
unknown, represented by the wildcard character ?.
Certain restrictions apply to genericized lists of unknowns, but if
you only want to call get() on the list and use the
result, such a list can be helpful.
If you are new to generics, you might assume that generic collections
are polymorphic. In that case, it would be correct to assign an
object of type List to an object reference of type
List. However, such assignments produce
compile-time errors.
With the current version of the Java Persistence API, code that uses
generics can produce spurious unchecked conversion
warnings. If other developers use your code, they might not realize
that they can safely ignore these warnings. You can use an annotation
to suppress the warnings.
Consider this innocent getAllItems() method, which
assigns query results to a generic list:
public List getAllItems(){
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT OBJECT(i) FROM Item i");
List items = query.getResultList();
em.close();
return items;
}
When this code is compiled with the -Xlint:unchecked
option enabled, it generates an unchecked conversion
message. The warning is generated because
query.getResultList() returns a nongenericized version
of List.
This warning is spurious because you know that the result of the
query is always a list of Item objects. Using a typecast
of (List) will not solve the problem because the
compiler does not preserve the generics type information for runtime.
You can suppress the warning by preceding the code block with the
annotation @SuppressWarnings("unchecked"). Needless to
say, you should use the @SuppressWarnings annotation
cautiously.