Move from container-managed persistence to the Java Persistence API Until the publication of the Enterprise JavaBeans 3.0 specification and the Java Persistence API, the only persistence technology officially part of the Java Enterprise Edition platform (Java EE is Sun’s new name for J2EE) was container-managed persistence (CMP) using EJB entity beans. Ever since they were first required to be supported in EJB 1.1, entity beans have been criticized as being both too complex and lacking in features to handle the persistence requirements of real-world applications. But standards matter in the enterprise, so despite the availability of proven object-relational mapping solutions, both commercial and open source, companies have always found a way to work around the entity bean shortcomings and get the job done. As a result, there is a large installed base of applications based on CMP entity beans, and bringing them forward into the next generation of Java EE standards may be a task worth pursuing.The complexity of entity beans lies not in the concept but in the implementation. Like session beans, entity beans are true EJB components, with separate classes for the bean implementation, home interface, and business interfaces. Entity beans also require a verbose XML deployment descriptor that describes the persistent properties of the bean, container-managed relationships between entities, and the EJB QL (query language) queries used to access the entities. Finally, many of the entity bean details require vendor-specific configuration to deploy and run. In response to these issues, the Java Persistence API offers a programming model that is easier to use, while offering a larger feature set with less vendor-specific configuration.Although the Java Persistence API is the standard persistence model moving forward, the good news for companies that have made an investment in CMP entity beans is that the EJB 3.0 specification still fully supports container-managed persistence. Existing applications will work out of the box without changes and can expect to do so for years to come. The EJB 3.0 specification is only now deprecating version 1.1 of the entity bean model. All Java EE 5-compliant application servers must support EJB 2.0 and 2.1 CMP entity beans. That’s good news for applications that aren’t likely to require much development going forward, but what about applications that are planning revisions? Is it feasible to move away from CMP and take advantage of the Java Persistence API? In many cases it will depend upon the design of your application. Only you can decide the most appropriate plan of action for your application. The following sections will lay out the issues and discuss potential strategies for migrating CMP applications to help you make your own decision.Note: This article assumes that you are familiar with EJB 2.1 container-managed entity bean implementation and configuration.Scoping the challengeThe challenge in moving from entity beans to entities is not the entity beans themselves. However complex they are to implement, they are relatively straightforward to use. The problem with entity beans is that the public API they expose is tightly coupled to the component model on which they are based. The principal issue facing any migration is the extent and manner in which application code interacts with entity bean interfaces. The more code that uses entity beans, the harder it is to migrate. There are also some entity bean features that are not reflected in the Java Persistence API. Some of these features, such as container-managed relationships, can be worked around, while others are difficult if not impossible to replace.The primary showstopper scenario is the use of remote entity bean interfaces. There is simply no equivalent to remote objects in the Java Persistence API. Entities are plain Java classes, not interface-based components that can be compiled down into RMI or Common Object Request Broker Architecture (CORBA) stubs. Entities are mobile in the sense that they can be serialized and transferred between client and server, but they are not network-aware. Ever since the EJB 2.0 specification introduced local interfaces, developers have been warned not to use remote interfaces on entity beans due to the overhead of the network infrastructure they require. If your application is one of the few, it is very unlikely that a migration would be possible until the application was refactored to use local interfaces.Tip Often, remote interfaces are used on entities only to facilitate transporting data off to a remote tier for presentation. Consider introducing the Transfer Object pattern to remove remote interfaces in these cases. Transfer objects share a strong symmetry with serializable entities, making them good starting points for migration. Applications that have isolated their persistence code, most likely through the use of one or more design patterns, present the least amount of effort to convert. Conversely, applications that sprinkle entity bean access across all tiers and are tightly coupled to the entity bean API present the greatest challenge. Refactoring to decouple business and presentation logic from persistence code is often a worthwhile exercise before attempting to migrate to the Java Persistence API. Two levels of application migration are discussed next. The first, documented in “Entity Bean Conversion,” details the process of mapping an existing entity bean to a new entity. From there, the developer can begin refactoring the application to introduce the entity manager and remove entity bean usage. The second level builds on the first by identifying business tier design patterns that present an opportunity to make a switch in persistence technologies with minimal impact to existing application code.Entity bean conversionWhen planning any conversion between entity beans and entities, it is useful to use the existing bean as a template for the new entity. The bean class, interfaces, and XML deployment descriptor describe the persistent fields used by the entity, the queries used by the application to find entity instances, and the container-managed relationships between entities. The following sections describe the process to convert an entity bean into an entity. Later sections will describe how to integrate these new entities into an existing application.Converting the business interfaceEntity beans are defined using a bean class, business interface, and home interface. When creating the initial entity version, the business interface or bean class can be used as a template. The business interface is often the best place to start as it defines the set of operations directly available on the entity as opposed to the bean class, which also includes home and finder methods specific to the home interface. Migrating propertiesTo demonstrate the process of migrating an entity bean to the Java Persistence API, we will look at converting an entity bean that stores information about a department. The business interface for the Department entity bean is shown in Listing 1.Listing 1. Department business interface public interface Department extends EJBLocalObject { public int getId(); public String getName(); public void setName(String name); public Collection getEmployees(); public void setEmployees(Collection employees); public Employee getManager();} To begin converting this interface into an entity, a concrete implementation of the interface must be provided, removing the dependency on EJBLocalObject and providing a field to implement each of the persistent properties. The properties id, name, and employees all map to either persistent fields or relationships. The getManager() method is actually a non-persistent business method that searches for and returns the manager for the department. Therefore, while the business interface is a good starting point, the bean implementation or the XML descriptor, which lists the persistent fields, must be consulted to determine the true meaning for each business method.With the set of persistent properties identified, the next step is to determine how they map to the database. Unfortunately, this mapping was not standardized by the EJB specification, so vendor-specific XML descriptors will have to be checked. For this example, assume that the entity bean maps to the table DEPT, which has columns ID and NAME. Setting aside the getManager(), getEmployees(), and setEmployees() methods for now, the entity implementation with basic mappings is shown in Listing 2. Because the entity name and table name are different, the @Table annotation is required to override the default table name of the entity.Listing 2. Department entity with basic mappings @Entity @Table(name="DEPT") public class Department { @Id private int id; private String name; public int getId () { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } Migrating business methodsNon-persistent business methods may be a source of problems during entity bean conversion. Many business methods simply perform operations using the persistent state of the entity (using the persistent getter methods to obtain data), and these may be copied to the new entity as is. However, the EJB specification also allows for business methods to invoke select methods in order to issue queries and operate on the results. Listing 3 shows a fragment from the DepartmentBean class, which defines the implementation of the getManager() method.Listing 3. Business method that uses a select method public abstract class DepartmentBean implements EntityBean { // ... public abstract Employee ejbSelectManagerForDept(int deptId); public Employee getManager() { return ejbSelectManagerForDept(getId()); } // ... } Select methods, which begin with the prefix “ejbSelect,” are container-provided implementations of EJB QL queries. They may be called by home methods (described later) and business methods. Business methods that invoke “ ejbSelect” methods pose a problem in entity bean conversion, as the entity manager required to execute the query is not typically available to entity bean instances. In this example, the select method issues the following query, which was defined in the XML descriptor: SELECT OBJECT(e) FROM Employee e WHERE e.department.id = ?1 AND e.manager.department.id <> ?1 To execute these queries from within the entity class, the entity manager must be made available to the entity instance. Since the entity manager is not part of the persistent state of the entity, it is strongly discouraged that you store a reference to it. Instead, consider the Service Locator pattern so that the entity manager can be obtained from within the entity even though it is not part of the entity. The following implementation of getManager() uses this approach: public Employee getManager() { EntityManager em = ServiceLocator.getInstance().getEntityManager("EmployeeService"); return (Employee) em.createNamedQuery("Department.managerForDept") .setParameter(1, getId()) .getSingleResult(); } The ServiceLocator class looks up the entity manager from JNDI (Java Naming and Directory Interface) using the current environment naming context. The downside to this approach is that entities tend to get used in a lot of different components, each with its own set of environment references. To ensure portability, the same entity manager reference name must be used consistently in all components, or some vendor-specific approach must be used to acquire the entity manager independent of context.Entity manager operations within an entity class are generally considered bad style as it introduces a dependency on the persistence runtime directly into the entity. This tightly couples the entity implementation to a particular persistence mechanism (the entity is no longer a plain Java object) and makes testing more difficult. Generally speaking, we recommend moving the business method to a session façade or other business-focused component instead of embedding entity manager operations within the entity class. The only consequence of moving the method to another class is that the entity needs to be passed as an argument to the method in its new location.Migrating container-managed relationships CMP entity beans may make use of container-managed relationships. These relationships are called managed because the developer is required to update only one side of the relationship and the server will ensure that the other side of the relationship is updated automatically. Although there is no direct equivalent to container-managed relationships in the Java Persistence API, the XML descriptor for these relationships can guide the definition of entity relationships for object-relational mapping.The Department entity bean has a one-to-many relationship with the Employee entity bean. Listing 4 shows the XML definition of the container-managed relationship between these two entity beans.Listing 4. XML definition of a container-managed relationship <ejb-relation> <ejb-relation-name>Dept-Emps</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>Dept-has-Emps</ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>DepartmentBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>employees</cmr-field-name> <cmr-field-type>java.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>Emps-have-Dept</ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>EmployeeBean</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>department</cmr-field-name></cmr-field> </ejb-relationship-role> </ejb-relation> Each side of the relationship is defined using the ejb-relationship-role element. The relationship-role-source and cmr-field elements define the entity bean and relationship property being mapped. The multiplicity element defines the cardinality of that side of the relationship. There is a direct mapping between each ejb-relationship-role element and a relationship annotation, the choice of which is determined by the multiplicity elements from each end of the relationship.Applying this pattern, the previous relationship descriptor maps to an @OneToMany annotation on the employees attribute of the Department entity and an @ManyToOne annotation on the department attribute of the Employee entity. Since the relationship is bi-directional, Employee will be the owner and Department the inverse, so the mappedBy element of the @OneToMany annotation is set to the name of the owning attribute, in this case department.We can now complete our mapping for the Department entity by adding the relationships. Listing 5 shows the complete entity class. Listing 5. Department entity with relationship mappings @Entity @Table(name="DEPT") public class Department { @Id private int id; private String name; @OneToMany(mappedBy="department") private Collection employees = new ArrayList (); public int getId () { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Collection getEmployees() { return employees; } } <code>Clients that used to use the relationship properties of the entity bean business interface require special attention when converted to use entities. Relationships that were previously managed by the container now require explicit maintenance to both sides of the relationship whenever a change occurs. In most cases, this amounts to one extra line of code. For example, adding an Employee entity bean to the employees property of the Department entity bean with container-managed relationships used to look like this: dept.getEmployees().add(emp); Without container-managed relationships, an extra step is required: dept.getEmployees().add(emp); emp.setDepartment(dept); Rather than adding these statements directly throughout application code, a best practice to consider is the use of helper methods on entities to manage relationships. The following example demonstrates these same operations as they would be implemented on the Department entity: public void addEmployee(Employee emp) { getEmployees().add(emp); emp.setDepartment(this); } Converting the home interfaceCreating an entity out of the entity bean business interface is often only the first step in conversion. Application code relies on the home interface to create new entity beans, find existing entity beans, and handle business methods that are related to an entity but not specific to any one entity bean instance.The first choice to be made regarding the home interface is whether or not application code will be rewritten to work directly with the entity manager. Doing so obsoletes most of the home interface operations, but it may be challenging to implement depending on how tightly coupled the entity bean API is to the application code. Business methods on the home interface also must be accommodated.If the home interface is still required, a stateless session bean may be used to provide equivalent methods to the home interface operations. The following sections continue the Department entity example by implementing a session façade for its business methods and finder operations.Migrating queriesEJB QL queries for CMP entity beans are defined in the deployment descriptor. Listing 6 shows two query definitions for the Department entity bean.Listing 6. EJB QL query definitions <query> <query-method> <method-name>findAll</method-name> <method-params/> </query-method> <ejb-ql>SELECT OBJECT(d) From Department d</ejb-ql> </query> <query> <query-method> <method-name>findByName</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql>SELECT OBJECT(d) FROM Department d WHERE d.name = ?1</ejb-ql> </query> To reuse these same queries with the converted entity bean, it is necessary to define named queries on the entity. Every EJB QL query is a legal JPQL (Java Persistence query language) query; therefore, existing EJB QL entity bean queries can be migrated without change to the Java Persistence API. The only thing we need to do is define a name for the query that will be unique across the persistence unit. To facilitate this, we will prepend the query name with the name of the entity. The following @NamedQuery annotations mirror the XML versions: @NamedQueries({ @NamedQuery(name="Department.findAll", query="SELECT d FROM Department d"), @NamedQuery(name="Department.findByName", query="SELECT d FROM Department d WHERE d.name = ?1") Migrating home methodsA home method is any method on the home interface that is not a finder (starts with “findBy“) or a create method (starts with “create“). They are also typically the easiest to integrate into a session façade, because their implementation often relies only on select methods. Home methods are implemented on the bean class in methods prefixed with “ejbHome“. Listing 7 shows a fragment of the DepartmentBean demonstrating a home method and the select method that it uses.Listing 7. Entity bean home method public abstract class DepartmentBean implements EntityBean { // ... public abstract Collection ejbSelectEmployeesWithNoDepartment() throws FinderException; public Collection ejbHomeUnallocatedEmployees() throws FinderException { return ejbSelectEmployeesWithNoDepartment(); } // ... } Assuming that the entity manager has been injected into the session bean, we can use the EJB QL query definition from the XML descriptor to re-implement this method: public Collection unallocatedEmployees() throws FinderException { try { return em.createQuery("SELECT e FROM Employee e WHERE e.dept IS NULL") getResultList(); } catch (PersistenceException e) { throw new FinderException(e.getMessage()); } } Creating the façadeWith queries mapped and home methods ready for conversion, creating the façade is straightforward. The advantage of a session bean is that it may be looked up from JNDI just as the entity home was previously and can use a similar interface in order to minimize application code changes. Listing 8 shows the home interface for the Department entity bean.Listing 8. The DepartmentHome interface public interface DepartmentHome extends EJBLocalHome { public Department create(int id) throws CreateException; public Department findByPrimaryKey(int id) throws FinderException; public Collection findAll() throws FinderException; public Department findByName(String name) throws FinderException; public Collection unallocatedEmployees() throws FinderException; } The first step in this refactoring is to modify the home interface so that it does not extend EJBLocalHome. With this dependency removed, the interface is now suitable for use as a stateless session bean business interface. Listing 9 shows the converted interface.Listing 9. The DepartmentHome business interface public interface DepartmentHome { public Department create(int id) throws CreateException; public Department findByPrimaryKey(int id) throws FinderException; public Collection findAll() throws FinderException; public Department findByName(String name) throws FinderException; public Collection unallocatedEmployees() throws FinderException; public void remove (Object pk) throws RemoveException; public void remove (Department dept) throws RemoveException; } Note the addition of the remove() methods. The first is the standard remove() method that is part of the EJBLocalHome interface, and the second is a convenience method that does not require the user to extract the primary key from the entity. Since entities do not implement EJBLocalObject, application code will no longer be able to invoke the remove() method directly on the entity bean. Invoking these methods is a compromise that allows application code to avoid directly using the entity manager while maintaining the ability to remove an entity instance. Application code will need to be refactored to change all invocations of remove() on the entity bean to one of these new methods on the session bean home façade.The next step is to create a session bean façade that implements the entity home interface. Using the techniques we have discussed so far, Listing 10 shows the complete stateless session bean implementation of the DepartmentHome interface. Note the use of checked exceptions on the bean methods. Until existing code is refactored to use the runtime exception model supported by the Java Persistence API, there may be client code that expects CreateException or FinderException exceptions to be thrown. We have also specified the name element for the @PersistenceContext annotation. This allows business methods such as the getManager() method we described earlier in the section “Migrating Business Methods” to access the entity manager from the “java:comp/env/EmployeeService” JNDI location.Listing 10. The DepartmentHome session bean @Stateless public class DepartmentHomeBean implements DepartmentHome { @PersistenceContext(name="EmployeeService", unitName="EmployeeService") EntityManager em; public Department create(int id) throws CreateException { Department dept = new Department(); dept.setId(id); try { em.persist(dept); } catch (PersistenceException e) { throw new CreateException(e.getMessage()); } catch (IllegalArgumentException e) { throw new CreateException(e.getMessage()); } return dept; } public Department findByPrimaryKey(int id) throws FinderException { try { return em.find(Department.class, id); } catch (PersistenceException e) { throw new FinderException(e.getMessage()); } } public Collection findAll() throws FinderException { try { return em.createNamedQuery("Department.findAll") getResultList(); } catch (PersistenceException e) { throw new FinderException(e.getMessage()); } } public Department findByName(String name) throws FinderException { try { return (Department) em.createNamedQuery("Department.findByDepartmentName") setParameter(1, name) getSingleResult(); } catch (PersistenceException e) { throw new FinderException(e.getMessage()); } } public Collection unallocatedEmployees() throws FinderException { try { return em.createNamedQuery("Department.empsWithNoDepartment") .getResultList(); } catch (PersistenceException e) { throw new FinderException(e.getMessage()); } } public void remove (Object pk) throws RemoveException { Department d = em.find(Department.class, pk); if (d == null) { throw new RemoveException("Unable to find entity with pk: " + pk); } em.remove(d); } public void remove(Department dept) throws RemoveException { Department d = em.find(Department.class, dept.getId()); if (d == null) { throw new RemoveException("Unable to find entity with pk: " +dept.getId()); } em.remove(d); } } SummaryMigrating the persistence layer of an application from one technology to another is rarely a trivial task. The differences between EJB container-managed entity beans and the lightweight entities of the Java Persistence API could make the task of migration tricky. And yet, despite these challenges, it is possible not only to extract enough information out of entity beans to bootstrap an object-oriented domain model, but also to leverage the same design patterns that made entity beans easier to work with as the very tool to replace them. In our discussion of entity beans, we looked at how to use the existing bean as a template for the new entity, using the business interface, bean class, and XML descriptor of the entity bean in the process. We also looked at the home interface and how we can introduce stateless session beans to emulate the functions of the home interface with minimal impact to application code. Michael Keith is the co-specification lead of EJB 3.0 and also a member of the Java EE 5 expert group. He holds a master’s of science in computing from Carleton University and has more than 15 years of teaching, research, and practical experience in object persistence. He has implemented persistence systems for Fortune 100 corporations on a host of technologies, including relational and object databases, XML, directory services, and custom data formats. Since the fledgling EJB days, he has worked on EJB implementations and integrations of multiple application servers. He has written various papers and articles and spoken at numerous conferences about EJB 3.0. He is currently employed at Oracle as a persistence architect. Merrick Schincariol is a senior engineer at Oracle and a reviewer of the EJB 3.0 specification. He has a bachelor’s of science in computer science from Lakehead University and has more than six years of experience in the industry. He spent some time consulting in the pre-Java enterprise and business intelligence fields before moving on to write Java/Java EE applications. His experience with large-scale systems and data warehouse design gave him a mature and practiced perspective on enterprise software that later propelled him into doing EJB container implementation work. He was a lead engineer for Oracle’s EJB 3.0 offering. Web DevelopmentData ManagementJava