ZDNet Asia

EJB Persistence with Java Standard Edition

DJ Walker-Morgan, Builder UK on April 21st, 2006 (April 21st, 2006)

Since EJB 3.0 was drafted, there's been a single, standard persistence mechanism for Java classes, whether in client- or server-side applications. Using Annotations, a feature of Java 5, it's simple to use, and we'll show you how.

Persisting Java classes; there have been so many ways to do it that the emergence of one standard for all is potentially a huge boon to developers. The challenge has been bridging the Java Standard/Enterprise gap, making a standard API which can work for enterprise applications running in managed containers and also work for standard applications which want to manage themselves, container free. And now we have one within JSR-220, the Enterprise Java Beans 3.0 specification. As JSR-220 developed, it split into two parts, EJB3.0 persistence and EJB 3.0 core (aka everything else).

EJB3.0 persistence is a different beast from previous EJB persistence, drawing on the addition of Annotations in Java 5.0 and the experiences of the various POJO persistence developers.

At the time of writing the EJB3.0 Persistence specification is in "Final Draft" and some elements are still fluid. Despite this, now is a good time to get your feet wet with a number of implementations of the spec available; the reference implementation is found in Glassfish, another implementation is Hibernate's Annotation and EntityManager projects.

Let's start with the basics; how to make a class persistable under Java SE. Here's a simple POJO:

public class Address {
private String street;
private String postcode;

public Address() {}

public String getStreet() { return street; }
public void setStreet(String street)
{ this.street = street; }

public String getPostcode() { return postcode; }

public void setPostcode(String postcode)
{ this.postcode = postcode; }
}

To make a class into an entity which can be persisted, we add the @Entity annotation at the start, to mark it as persistable like so:

import javax.persistence.Entity;

@Entity
public class Address {
...

Now, if your first reaction is "Hey, what's an @Something", let me briefly introduce annotations. Java has historically lacked a way of embedding metadata in code. Javadoc was a kind of metadata, for generating documentation and that worked by using tags prefixed with @ in comment blocks. This idea was built on with XDoclet, which people have used to carry their own metadata. An alternative approach was to have matching XML files for classes, for example Hibernate used a .hbm.xml file along side the class to carry its mapping information for the same named class. Both techniques have served well, but for Java 5, there was a desire for a more inline, compiler verifiable and discoverable at run time implementation; this is where Annotations come in. For our purposes, all you need to know is that annotations are how we add metadata about how to persistently map a class.

The @Entity annotation marks the class for persisting. To be easily retrievable, the POJOs are going to each need a primary key. One common way of doing this is to introduce a long field to act as that key. So we'll add this to the classes:

private Long id;

@Id
@GeneratedValue
public Long getId() { return id; }
public void setId(Long id) { this.id=id; }

The @Id annotation marks the getter as the primary key field and the @GeneratedValue annotation asks the persistence layer to generate a value for this field. And that's all we need to do; we can now move on to working with an Address.

Address address=new Address();
address.setPostcode("ZZ9 99Z");
address.setName("John Doe");

For us to persist Address, we need an EntityManager which we get for each unit of work we want to do with our persistent data. This is the big difference between persistence under Java EE and Java SE; in Java EE, there are annotations to allow the surrounding framework to manage the entities. In Java SE, the responsibility is passed to the developer to obtain an EntityManager. We get an EntityManager from an EntityManagerFactory.

EntityManagerFactory emf=null;

EntityManager em=emf.getEntityManager();

We'll come back to where we get the EntityManagerFactory from later; for now, assume it's initialised and we can get an EntityManager from it. When you are persisting with Java SE you also have responsibility for managing database transactions; you have to begin and end database transactions, so let's get a transaction and begin it;

EntityTransaction tx=em.getTransaction();
tx.begin();

Now we can ask the EntityManager to persist our Address.

em.persist(address);

And commit the transaction and close the EntityManager;

tx.commit();
em.close();

After this, an id will have been assigned to our Person, and it will be written out to the database. That pattern of getting a transaction and committing it is common to any code which is going to modify the persistent state of objects. For reliability, it should catch exceptions and roll back when there is an issue like so.

EntityManager em=emf.getEntityManager();
EntityTransaction tx=em.getTransaction();

try {
tx.begin();

// Do saves or modifications here

tx.commit();
} catch (Exception e) {
if(tx.isActive()) tx.rollback();
System.err.println("Error:"+e);
} finally {
em.close();
}

Assume this code is surrounding the following examples where we modify the database. For retrieving data, we only need to get the EntityManager.

To retrieve that Address we saved earlier, we can use the id as a reference; we don't need a transaction from the EntityManager so it becomes simply;

Address address2=em.find(Address.class,address.getId());

If we want to find an Address by postcode, we can use EJB Query Language, EJBQL to define a query, and get the EntityManager to create that query.

Query q=em.createQuery("select address
from Address as address where postcode=:param");

The query expands out as find addresses (from however Address is persisted and return the results as Address objects) where the address has a postcode which matches the 'to be set' parameter named "param". We can set that parameter now;

q.setParameter("param",name);

And to get the result, call getResultList on the query if we are expecting 0 or more results, or call getSingleResult() if we are expecting only one result.

List<Address> l=(List<Address>)q.getResultList();

or

Address addresstochange=(Address)q.getSingleResult();

The last thing we need to do is be able to is be able to change an Address and merge its changes with the database; assume we have retrieved a single Address in that previous query.

addresstochange.setStreet("A Different Street");

em.merge(addresstochange);

Here's another POJO, Person, which we've already annotated for persisting;

@Entity public class Person { private Long id; private String name; private Address address; public Person() {} @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id=id; } public String getName() { return name; } public void setName(String name) { this.name=name; } @ManyToOne public Address getAddress() { return address; } public void setAddress(Address address)
{ this.address = address; } }

This important part of this is the @ManyToOne annotation for the address field. The @ManyToOne annotation is one of a set for describing the relationship between entities; in this case it denotes many persons may reference one address. This needs to be a reference to an already persisted address.

Person person=new Person(); person.setName("John Doe"); person.setAddress(address); … em.merge(person); …

The merge method is smart about entities handed to it; if the entity is unmanaged, it will persist it, otherwise, it will work out the differences and update the database as appropriate. That takes care of the Person being persisted.

And that's the basics of persisting. Apart of course from that EntityManagerFactory we assumed existed. This is where the rubber meets the road. This is a typical call to create it.

EntityManagerFactory
emf=Persistence.createEntityManagerFactory("example");

We ask the Persistence layer to build a factory for us based on the name "example". The configuration information used to create this factory comes from a file called persistence.xml which should be kept in the META-INF directory in your source tree. It defines a named "persistence-unit" which has the details of how persistence should be managed, which underlying persistence provider will do the work, and which database to use. Here's a snippet;

<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="example"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>quick.Person</class> <class>quick.Address</class> <properties> … </properties> </persistence-unit> </persistence>

Here we have a persistence-unit named "example" which is the name we gave to createEntityManagerFactory(). We're using the Hibernate Annotations/EntityManager combination, so the <provider> element points to the HibernatePersistence provider. You can have one or more <class> elements, each one will point to a class which you want to be persistent. In the example, you can see class elements for the Person and Address. There's also a <properties> element which contains <property> elements for setting implementation specific values to be passed to the created EntityManagerFactory. In our example setup, we're using Hibernate and HSQLDB embedded. We need to set the JDBC driver to use a URL to connect to the database and tell Hibernate what dialect of SQL to use;

<property name="hibernate.connection.driver_class"
value="org.hsqldb.jdbcDriver"/> <property name="hibernate.connection.url"
value="jdbc:hsqldb:data/example"/> <property name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>

The embedded HSQLDB starts up with a username of "sa" and a blank password. We also want to limit how deep hibernate fetches related objects.

<property name="hibernate.connection.username" value="sa"/> <property name="hibernate.connection.password" value=""/> <property name="hibernate.max_fetch_depth" value="3"/>

Finally, the hbm2ddl.auto property. This controls the ability of the Hibernate to dynamically create needed tables in the SQL database. Set to "create", it will clear the database and generate new tables each time it's run. Set to "update" it will attempt to modify existing tables to be suitable for the current versions of entities;

<property name="hibernate.hbm2ddl.auto" value="create"/>

Generating the DDL to create the database is something that should be available in most implementations, but the switch to turn it on currently varies between implementations.

With this XML file in place, you now have enough information for createEntityManagerFactory to be able to create the simple database. You'll find this persistence.xml and example code in the source code accompanying this article. To get it to run though you'll need the appropriate libraries. First up, you'll want the HSQLDB database, Hibernate, Hibernate-Annotations and Hibernate-EntityManager from the Hibernate Web site. See the readme file with the source for which libraries you'll need from where. Once you have the example running, you can start experimenting with creating and persisting a simple entity. If you want to see what is being executed as SQL add:

<property name="hibernate.show_sql" value="true"/>

to the persistence.xml properties. Hibernate will then also dump each SQL statement it's executing under the covers.

Now, we've got in place the basics of persisting and some simple mapping. Next month, we look at more of the annotations available, how to persist collections and take a look at the reference EJB persistence implementation in Glassfish.

You can download the source code for this tutorial here.

Resources

DJ Walker-Morgan is a consulting developer, specialising in Java and user-to-user messaging and conferencing.

URL:http://www.zdnetasia.com/ejb-persistence-with-java-standard-edition-39352492.htm