About a year ago, with the help of Spring and Hibernate, I escaped from the EJB cult which had held me captive for five long years. It was such a relief to no longer perform the painful EJB development rituals that I had been brainwashed into believing were a good thing. With Spring and Hibernate I was able to develop and test POJO business logic without having to wait for my code to deploy in an application server. I had the freedom to map a complex domain model to database schema. I could develop loosely coupled, easy to test, transactional components. Life without EJB was pretty good. So it was with some trepidation that I began to port the sample application from my book to EJB3 using JBoss EJB 3 preview 5, which conforms to the February 2005 specification.
About the application
The example application is the order processing system for a fictitious company that delivers takeout orders from restaurants to customer’s homes and offices. The business tier consists of a domain model that is encapsulated by a façade. Originally, it was an EJB application. The domain model consisted of entity beans encapsulated by a session façade. In the second version the entity bean domain model was replaced with a POJO domain model that used JDO for persistence. The latest version has a POJO domain model, which uses either Hibernate or JDO for persistence, and a POJO façade, which uses Spring AOP for transaction management.
Overview of the domain model
The first step in porting the application to EJB3 was to migrate the domain model from JDO/Hibernate so let’s have a look at its structure. The following diagram shows some of the persistent classes.

The key classes are as follows:
The object/relational mapping for this domain model is pretty straightforward:
All of this is handled quite easily by JDO and Hibernate. So what about EJB3?
Persisting the domain model with EJB3
I want to start off by saying that EJB3 persistence is huge improvement over EJB2 CMP. Entity beans are very POJO-like and do not have to implement any special interfaces or any boilerplate methods etc. To make a class persistent you simply have to add an @Entity annotation to the class and annotate some of its fields. However, as I described previously the current version of the draft specification has many significant limitations that impact the design of simple domain model like this one. Consequently, I had to change many of the classes.
No support for persistent interfaces or abstract classes
The first problem is that EJB3 currently does not support persisting interfaces or abstract classes. I had to turn the Coupon interface into a concrete class:
@Entity(access = AccessType.FIELD)
@Table(name = "FTGO_COUPON")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE, discriminatorType = DiscriminatorType.STRING)
@DiscriminatorColumn(name = "COUPON_TYPE")
public class Coupon implements Serializable {
@Id(generate = GeneratorType.AUTO)
private int id;
private String code;
public Coupon() {
}
protected Coupon(String code) {
this.code = code;
}
public String getCode() {
return code;
}
// TODO - must be overriden
public double getDeliveryChargeDiscount(
PendingOrder pendingOrder) {
throw new RuntimeException(
"Must be implemented by subclass");
}
// TODO - must be overriden
public double getSubtotalDiscount(
PendingOrder pendingOrder) {
throw new RuntimeException(
"Must be implemented by subclass");
}
}
This is pretty nasty especially because you are forced to implement methods that should be abstract.
No support for lists
One-to-many relationships such as PendingOrder-PendingOrderLineItem and Restaurant-MenuItem are implemented by lists:
class PendingOrder {
List<PendingOrderLineItem> lineItems;
}
Sadly, the current EJB 3 specification does not let you persist lists. Like EJB2 you can only persist sets or collections and so I had to make the following change:
@Entity(access = AccessType.FIELD)
@Table(name = "FTGO_PENDING_ORDER")
class PendingOrder {
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name="PENDING_ORDER_ID",referencedColumnName="ID")
protected Collection<PendingOrderLineItem> lineItems;
}
On a positive note I was happy to discover that JBOSS EJB 3 supports the unidirectional one-to-many foreign key mapping, which for some strange reason is currently an optional feature of the EJB 3 spec.
No support for collections of primitive types
A restaurant’s serviceArea is a collection of Strings:
class Restaurant {
protected Set<String> serviceArea;
}
Unfortunately, the current EJB3 specification does not you persist collections of non-entities. I had to define a ZipCode entity bean that wraps the String and has many-to-many relationship with the Restaurant:
@Entity (access=AccessType.FIELD)
@Table(name="FTGO_RESTAURANT")
class Restaurant {
@ManyToMany
protected Set<ZipCode> serviceArea;
}
This is very unfortunate because POJO domain models often have collections of non-entities.
No support for defining the mapping for doubly embedded classes
Defining the mapping for PendingOrder.address was pretty straightforward using the @AttributeOverride annotation:
class PendingOrder {
@Embedded( {
@AttributeOverride(name = "street1", column = { @Column(name = "DELIVERY_STREET1") }),
@AttributeOverride(name = "street2", column = { @Column(name = "DELIVERY_STREET2") }),
@AttributeOverride(name = "city", column = @Column(name = "DELIVERY_CITY")),
@AttributeOverride(name = "state", column = @Column(name = "DELIVERY_STATE")),
@AttributeOverride(name = "zip", column = @Column(name = "DELIVERY_ZIP")) })
private Address deliveryAddress;
However, it turns out that you currently cannot write annotations in the parent class that define the mapping for doubly embedded objects such as PendingOrder.paymentInformation.address. I had to use @AttributeOverride inside the PaymentInformation class to change the mapping for PaymentInformation.address, which incorrectly assumes that PaymentInformation is only used in one place.
Summary
Some aspects of using EJB3 persistence are quite straightforward. For example, because it has sensible defaults for the object/relational mapping you can start off by only using minimal annotations. However, as you can see, the current EJB3 persistence specification supports only some of the basic requirements of a POJO domain model. You must make significant changes to even a simple domain model.
In the next installment I will describe the classes that use the EntityManager to create, find and delete persistent objects.
"No support for defining the mapping for doubly embedded classes"
"No support for defining the mapping for doubly embedded classes"
Thanks to your comments, I found the reason why my List-based OneToMany
relationships were not persisted, regardless of the cascade settings.
"The first problem is that EJB3 currently does not support persisting
interfaces or abstract classes. I had to turn the Coupon interface into a
concrete class:"