The major theme of version 5 of the Java Platform, Enterprise Edition (Java EE, formerly referred to as J2EE) is ease of development. Changes throughout the platform make the development of enterprise Java technology applications much easier, with far less coding. Significantly, these simplifications have not changed the platform's power: The Java EE 5 platform maintains all the functional richness of the previous version, J2EE 1.4.
Enterprise developers should notice dramatic simplification in Enterprise JavaBeans (EJB) technology. Previous articles, such as Introduction to the Java EE 5 Platform and Ease of Development in Enterprise JavaBeans Technology have described the simplifications made in EJB 3.0 technology, an integral part of the Java EE 5 platform.
A major enhancement in EJB technology is the addition of the new Java Persistence API, which simplifies the entity persistence model and adds capabilities that were not in EJB 2.1 technology. The Java Persistence API deals with the way relational data is mapped to Java objects ("persistent entities"), the way that these objects are stored in a relational database so that they can be accessed at a later time, and the continued existence of an entity's state even after the application that uses it ends. In addition to simplifying the entity persistence model, the Java Persistence API standardizes object-relational mapping.
In short, EJB 3.0 is much easier to learn and use than was EJB 2.1, the technology's previous version, and should result in faster development of applications. With the inclusion of the Java Persistence API, EJB 3.0 technology also offers developers an entity programming model that is both easier to use and yet richer.
This article supplements the earlier articles by focusing on entity-related code. Here you'll be able to examine EJB 2.1 entity beans in an application and compare them to EJB 3.0 entities in an equivalent application. More specifically, you'll be able to view side by side the source code for EJB 2.1 entity beans that use container-managed persistence and relationships and compare them to the source code for equivalently functioning EJB 3.0 entities written to the Java Persistence API. Note that in the Java Persistence API, what used to be called entity beans are now simply called entities. You'll see how much easier and streamlined the EJB 3.0 technology code is.
The article highlights some of the important features that simplify the EJB 3.0 version of the code. Although this article focuses on the Java Persistence API and its use in an EJB 3.0 container, the API can also be used outside the container -- for instance, in applications for the Java Platform, Standard Edition (Java SE, formerly referred to as J2SE). The API also provides support for pluggable, third-party persistence providers. For example, a persistence implementation from one vendor can be used with an EJB container from another vendor, provided that the container and the persistence implementation both conform to JSR 220.
This article assumes that you're familiar with the basic concepts of EJB technology that underlie EJB 2.1. If you're not, see the chapter "Enterprise Beans" in the J2EE 1.4 Tutorial. For more information about EJB 3.0 and Java Persistence concepts, see the chapter "Enterprise Beans" in the Java EE 5 Tutorial.
First, let's look at the application in use.
This article uses the EJB 2.1 technology version of the application, the CMP Customer Sample Application, from the J2EE 1.4 samples bundle. You can download the samples bundle from the J2EE 1.4 Downloads page. The samples bundle includes instructions for installing and running the EJB 2.1 version of the application.
The EJB 3.0 version of the same application is called the Java Persistence Demo and is available for download here. The download bundle includes instructions for installing and running the EJB 3.0 version of the application.
Both versions of the application do the same thing: They interact with a relational database to store and display information about customer subscriptions to periodicals. The database stores information such as a customer's name and address, as well as the type of periodical to which the customer is subscribed -- that is, magazine, journal, or newspaper. You can submit requests to the application to display subscription-related information. For example, you can get a list of all subscriptions for a particular customer.
Figure 1 shows what some of the interactions look like. Click to enlarge each image.
Let's examine the entity-related code within the application. First, let's look at what classes and interfaces are required for the entities in the application. Look at Figure 2. Compare the list in the EJB 2.1 version with that of the EJB 3.0 version.
You need to code fewer classes and interfaces
For an EJB 3.0 entity, you no longer need to code interfaces such as
Let's now look at the code for the entities. Let's start by comparing some of the key parts of the code for the EJB 2.1
An entity is a Plain Old Java Object (POJO), so no boilerplate is required
The EJB 2.1 version of the entity bean class implements the
By comparison, an EJB 3.0 entity class is a simple, nonabstract, concrete class -- a POJO, a class that you can instantiate like any other simple Java technology class, with a
Annotations minimize what needs to be specified
Defaults make things even easier
In many cases, the application can use defaults instead of explicit metadata annotation elements. In these cases, you don't have to completely specify a metadata annotation. You can obtain the same result as if you had fully specified the annotation. For example, the
Let's now compare how persistence is declared for fields and properties.
Persistence declarations are simpler
In EJB 2.1 technology, you specify which fields of the class need to be persisted in a database by defining public abstract getter and setter methods for those fields and by making specifications in a deployment descriptor -- an approach that many programmers find clumsy and far from intuitive. EJB 3.0 technology does not require these specifications. In essence, persistence is built into an entity. The persistent state of an entity is represented either by its persistent fields or persistent properties.
Recall that an entity is a POJO.
Like a POJO, it can have nonabstract, private instance variables, such as the
No XML descriptor needed to declare persistent fields
EJB 2.1 technology, entity bean fields are identified as persistent fields in the bean's deployment descriptor,
Default mappings are used where possible
In EJB 2.1 technology, you define the mapping between an entity bean's fields and their corresponding database columns in a vendor-specific deployment descriptor, such as
The Java Persistence API standardizes object-relational mapping, enabling fully portable applications.
There are also simplifications in the way primary and composite keys for entities are specified.
No XML descriptor needed to specify the primary key
In EJB 2.1 technology, the primary key for an entity bean -- that is, its unique identifier -- is specified not in the entity bean class
but rather in its deployment descriptor. In the Java Persistence API, you don't need to provide an XML descriptor to specify an entity's primary key.
Instead, you specify the primary key in the entity class by marking an appropriate persistent field or persistent property with the
So far, the focus has been on the coding simplifications that relate to basic persistence, that is, the persistence of entities and their fields or properties. Now, let's look at the coding simplifications that relate to entity relationships. To do that, let's focus on the
Relationship declarations are simpler
Specifying container-managed relationships in EJB 2.1 technology can be quite complex. If entity bean A has a relationship with entity bean B, you must specify abstract getter and setter methods in entity bean A for the related entity bean B. In addition, you must provide a rather lengthy entry for the relationship in the
Note, however, that unlike in EJB 2.1 with container-managed persistence, the application that uses the Java Persistence API is responsible for managing relationships. For example, unlike EJB 2.1 technology, the Java Persistence API requires the backpointer reference in a bidirectional relationship to be set. Assume entity A has a bidirectional relationship to entity B. In EJB 2.1 technology, all you need to do is set the relationship from A to B -- the underlying persistence implementation is responsible for setting the backpointer reference from B to A. The Java Persistence API requires the references to be set on both sides of the relationship. This means that you have to explicitly call
Annotations specify multiplicity and related information
You declare the relationships in annotations that reference the related entities. Annotations on the persistent fields and properties specify the multiplicity of a relationship, such as one-to-many or many-to-many, and other information, such as cascade and eager fetching. (By comparison, in EJB 2.1 technology, this information is specified in vendor-specific settings.) For example, the
The owning side specifies the mapping
Notice that the many-to-many relationship between the
Default mappings are used for relationships where possible
You can take advantage of default mappings to simplify the coding for relationship mapping even further. If you look at the create.sql file under the
An important capability of the Java Persistence API is its support for inheritance and polymorphism, something that was not available in EJB 2.1. You can map a hierarchy of entities, where one entity subclasses another, to a relational database structure, and submit queries against the base class. The queries are treated polymorphically against the entire hierarchy.
The code in the EJB 3.0 column below shows an example of the support for inheritance and polymorphism. This sample is not taken from the application code because the Java Persistence Demo does not use this feature. Here,
Annotations specify inheritance
Defaults can be used for various inheritance specifications
As is the case in many other parts of EJB 3.0 technology and the Java Persistence API, you can rely on defaults to further simplify coding. For example,
Entities can inherit from other entities and from non-entities
The EJB 3.0 example illustrates inheritance from an entity. However inheritance from POJOs that are not entities -- for behavior and mapping attributes -- is also allowed. The base entity or nonentity can either be abstract or concrete.
Another pronounced simplification in the Java Persistence API is the way entity operations are performed. For example, look at the way a subscription is removed in the
Entity operations are performed directly on the entity
In EJB 2.1 technology, a client must use the Java Naming and Directory Interface (JNDI) to lookup the bean. In doing this, JNDI acquires an object that represents the bean's home interface. In response, the EJB container creates an instance of the bean and initializes its state. The client can then call methods on the JNDI-acquired object to perform operations on the bean. In the EJB 2.1 technology code sample above, JNDI is used to acquire an object that represents the
By comparison, the Java Persistence API requires no JNDI-based lookup. An
An entity manager manages the entities
Dependencies can be injected
As illustrated in the EJB 3.0 technology code example in Figure 8, JNDI is no longer required to get references to resources and other objects in an enterprise bean's context. Instead, you can use resource and environment reference annotations in the bean class. These annotations inject a resource on which the enterprise bean has a dependency. In the EJB 3.0 technology code sample, the
Transaction-related specifications are also simplified.
No XML descriptor needed to specify transaction attributes
In EJB 2.1 technology, you specify the transaction attributes for container-managed transactions in an often lengthy and complex deployment descriptor. In EJB 3.0 technology, an XML descriptor is not needed to specify transaction attributes. Instead, you can use the
Container-managed entity managers are Java Transaction API entity managers
In the Java Persistence API, transactions involving
Support for queries has been significantly enhanced in the Java Persistence API. Some of these enhancements are shown in Figure 10.
No XML descriptor needed to specify queries
In EJB 2.1 technology, you define a query for an entity bean using Enterprise JavaBeans query language (EJB QL). You specify the query in the deployment descriptor for the bean, and associate it there with a finder or select method for the bean. In the Java Persistence API, you can define a named -- or static -- query in the bean class itself. You also have the option of creating dynamic queries. To create a named query, you first define the named query using the
Support for dynamic queries and named queries is added
The Java Persistence API provides a Query API to create dynamic queries and named queries. For example, the
All queries that use the Java Persistence API are polymorphic
This means that when a class is queried, all subclasses that meet the query criteria are also returned.
The Java Persistence Query Language is an enhanced query language
EJB QL has been a very popular facet of EJB technology. However, despite its popularity, EJB QL has lacked some of the features of a full structured query language, such as bulk update and delete operations, outer join operations, projection, and subqueries. The Java Persistence query language adds those features. It also adds support for outer join-based prefetching. The full range of the Java Persistence query language can be used in static or dynamic queries. However the Java Persistence Demo does not use the Java Persistence query language enhancements.
Although this can't be demonstrated in a side-by side code comparison, testing entities outside an EJB container is now much easier. Previously, the entity bean component model -- with its requirements for home and component interfaces, abstract entity bean classes, and virtual persistent fields -- made it difficult to test entity beans outside of the container. The Java Persistence API removes the requirement for these interfaces. The only thing required for an entity bean is a concrete entity bean class -- a POJO -- that has persistent fields or persistent properties. In addition, an entity's life cycle is controlled through the entity manager, not through a home interface whose life-cycle methods are implemented by the EJB container. Because all of this makes entities less dependent on intervention by the EJB container, the entities can be more easily tested outside of the container.
The aim of the new Java Persistence API is to simplify the development of persistent entities. It meets this objective through a simple POJO-based persistence model, which reduces the number of required classes and interfaces. You model your data using POJOs, and then annotate them to tell the container about an entity's characteristics and the resources it needs. You also use annotations for object-relational mappings and entity relationships, as well as deploy-time instructions. This annotation-based approach removes the need for often long and complex, XML-based descriptors. In many cases, the annotations' defaults are enough. You code specific attributes of the annotations only when the defaults are inadequate.
Beyond these simplifications, the Java Persistence API adds capabilities that were not in EJB 2.1 technology, giving you additional power and flexibility in developing and using persistent entities. You can take advantage of query language enhancements and new features such as inheritance and polymorphism to perform more powerful and encompassing queries. You can exercise more control over queries, and perform query optimizations specific to your needs. In short, using the Java Persistence API is much simpler and more intuitive than it's predecessors, yet it offers a more robust API for creating, managing, and using persistent entities.
This article only highlights the simplifications and enhancements that the Java Persistence API offers. You'll find more extensive information about the API, as well as other simplifications made in EJB 3.0 technology, by examining the Enterprise JavaBeans 3.0 Specification. Now is a good time to try out EJB 3.0 technology and the Java Persistence API. See the Try It Out! box at the beginning of this article for some good places to start.
Rahul Biswas is a member of the Java Performance Engineering group at Sun. He is currently involved in the development of a generic performance benchmark for Java Persistence and the performance improvement of the persistence implementation in GlassFish.