Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Banish Your Resistance to Persistence with the EJB 3.0 Persistence API : Page 5

With the 3.0 version of EJB, Java's guardians have endeavored to make persistence a gentler beast that borrows the best from other ORM frameworks that have long curried favor with the community. Now, learn how to use the new spec, along with JBoss and Maven, to persist Java objects to a relational database.


WEBINAR: On-Demand

Unleash Your DevOps Strategy by Synchronizing Application and Database Changes REGISTER >

In addition to being able to map entities related by containment to a database, EJB 3.0 also allows entities related through inheritance to be mapped and persisted. There are three strategies to accomplish this:
  • Single table per class hierarchy—Create one table and place within it all data related to the hierarchy of objects. A discriminator column is added to indicate each table row's object type.
  • Single table per class—Each subclass is mapped to a separate table.
  • Joined subclasses—Fields common to all classes in the hierarchy are placed in one table. Each subclass has its own table with fields specific only to that subclass.
These three strategies are illustrated below in Figure 5.

Figure 5. Inheritance Mapping Strategies. There are three mapping strategies that you can choose from to map inherited entities to a database. Each strategy has its own tradeoffs in terms of duplication and complexity.
You specify the mapping strategy, and optionally the discriminator value, in the @Inheritance annotation applied to the subclasses. The default mapping strategy (and the one used in the example application) is the table per class hierarchy strategy. This is illustrated in the below code snippets from the Product, Album, and Video classes, respectively.

@Entity(access = AccessType.FIELD) public abstract class Product implements Serializable { @Id(generate = GeneratorType.AUTO) private int id; private String title; private String description; @ManyToOne private Artist artist; ... } @Entity(access = AccessType.FIELD) @Inheritance(discriminatorValue = "A") public class Album extends Product { private int tracks; ... } @Entity(access = AccessType.FIELD) @Inheritance(discriminatorValue = "V") public class Video extends Product { private int length; ... }

Notice how both classes specify a unique discriminator value. This value is used by the persistence framework to determine the underlying Java type of the object from the relational data. With this strategy, the class hierarchy is flattened when it is persisted to the database. Figure 6 shows some sample objects from the Product class hierarchy, which have been persisted.

Figure 6. Relational Representation of Product Hierarchy. The hierarchical representation of products has been flattened into a single relational table. Each row of the table contains all of the fields represented in the hierarchy. The type (or discriminator) is used to determine the underlying type of each row in the table.
In Figure 6, note that rows having a type of "A" represent Album objects while rows having a type of "V" represent Video objects. The length column is unnecessary and wasted on Album objects while the tracks column is unnecessary and waster on Video objects. This design trades off wasted space for the simplicity of only having one table to deal with.

Packaging and Deployment
As mentioned earlier in this article, each persistence unit is packaged into a single archive named a persistence archive. This archive includes the set of managed entity classes, their supporting metadata, and a named entity manger. All of these artifacts are included in the persistence archive, which is given the extension .par.

The classes and their accompanying metadata are stored in the PAR just as normal Java classes are stored in a JAR. The entity manager is specified and configured in a descriptor named persistence.xml. This descriptor is stored in the META-INF directory of the PAR just as an ejb-jar.xml file is stored in the META-INF directory of an EJB-JAR. The persistence.xml file for the music store example is shown below:

<entity-manager> <name>musicStoreDB</name> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> </properties> </entity-manager>

The name element specifies the name of the entity manager. This name corresponds to the unitName attribute of the @PersistenceContext annotation used to inject EntityManager instances. The jta-data-source element (and its twin the non-jta-data-source element) specifies the JNDI name of the JTA (or non-JTA) datasource to be used. In the case of JBoss the DefaultDS data source is provided by default. And you can optionally specify a non-default persistence provider through the provider element. For more information on configuring a persistence.xml file refer to the EJB 3.0 specification.

Additionally you can specify provider-specific properties in the properties section of this descriptor. Since by default JBoss uses Hibernate as its underlying persistence provider I have defined some Hibernate specific properties in this section. For more information on the specific properties that are allowable in this section consult the documentation for your persistence provider.

The .par file should be included in your application Enterprise Archive (EAR) file just as other J2EE modules are. Additionally you need to specify the .par in the application.xml file of your EAR. An sample from the music store example is shown below:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd"> <application> <display-name>music-store-deploy</display-name> <module> <ejb>music-store-domain-1.0-SNAPSHOT.ejb3</ejb> </module> <module> <java>music-store-entity.par</java> </module> <module> <java>music-store.aop</java> </module> <module> <web> <web-uri>music-store-web.war</web-uri> <context-root>/music-store-web</context-root> </web> </module> </application>

The music store example application uses Maven 2.0 as its build tool. The maven-ear-plugin builds this application.xml file automatically from the project metadata specified in the pom.xml file of the music-store-deploy project. For more information on this please download and consult the example source code accompanying this article.

In this article you have seen how to use the EJB 3.0 persistence API to persist Java objects to a relational data store. Specifically, you have seen how to use metadata annotations to map objects to relational entities, how to use the EntityManager to make objects persistent, and to retrieve persisted objects from the database.

Stayed tuned for my next article looking at how transaction management, security, and exception handling are addressed in EJB 3.0. I will also return to Enterprise Bean Components and show how callbacks and interceptors can be used to add additional functional to these components.

Rod Coffin is an agile technologist at Semantra, helping to develop an innovative natural language ad hoc reporting platform. He has many years of experience mentoring teams on enterprise Java development and agile practices and has written several articles on a range of topics from Aspect-Oriented Programming to EJB 3.0. Rod is a frequent speaker at user groups and technology conferences and can be contacted via his home page.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date