Summary
A recent article by Jeff Brown provides a hands-on overview of the EJB 3 persistence model. His examples use Hibernate as the EJB 3 persistence provider, and illustrate how Java 5 annotations alleviate the need for XML mapping files.
Advertisement
The EJB 3 persistence model is at the core of J2EE 5, offering a simplier, light-weight model compared with earlier EJB specifications. The new model took into account experience with managed beans in prior J2EE releases, as well as practical advice from the Hibernate and JDO communities.
The most important difference from earlier EJB versions is that the EJB 3 persistence model can be used both within and without a container, and requires only a compatible persistence provider implementation. A J2EE server might offer such an implementation, and Hibernate 3 also happens to be a light-weight EJB 3 persistence provider.
In his recent EJB 3 tutorial, Jeff Brown shows how to persist a POJO, how to map relationships using annotations, and how to query an EJB 3 provider. While his examples use Hibernate, the only Hibernate-related information is in the persistence context descriptor, which is the only XML file required by the persistence model.
Jeff shows that a POJO must meet these four requirements to be persistable in the EJB 3 model:
Must have a no-arg constructor
Must not have any final methods
Its class must not be final
The class must be marked with @Entity, or have an associated XML descriptor
The annotation-based model alleviates the need for XML descriptor files. For instance, the article shows that by associating a few annotations with a POJO, an instance of this class can be persisted via any EJB 3 persistence provider:
@Entity
public class Person {
private String firstName;
private String lastName;
private Integer id; // new field to represent identity
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String toString() {
return lastName + ", " + firstName;
}
}
Persisting an instance of this class is as simple as the following code snippet:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("mycontext",
new HashMap());
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(new Person("Ben", "Franklin"));
tx.commit();
em.close();
The persistence context descriptor can even define if the persistence manager should create a new table, if one for this entity does not already exist:
Here, the hibernate.hbm2ddl.auto property is set to update, indicating that a table should be updated to reflect the bean's properties. Again, this is the single XML file required by the persistence model.
This is not a comment on EJB3 but a comment on the use of Factory pattern. I see this type pf code very often:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(
"mycontext", new HashMap());
EntityManager em = emf.createEntityManager();
Notice that in order to use the EntityManager class, the user (developer) must be aware of the existence of the EntityManagerFactory class and the Persistence class even though these two classes play no further role in the code. This strong coupling seems unnecessary.
Why should the developer know that there is a factory used to create the EntityManager? Why can't this fact be hidden within the innards of the EntityManager class? We could use code like:
EntityManager em =
EntityManager.createEntityManager(
"mycontext", new HashMap());
The EntityManager class can transparently invoke the Factory to get the instance by calling the first line of the code quoted above. Why should the developer be aware of the implementation details of EntityManager class? What benefit does it provide?
In fact, if a new instance of EntityManager were to be provided with every call, why couldn't one simply use the following:
EntityManager em =
new EntityManager("mycontext", new HashMap());
Going to the next step, we'd immediately observe that an overloaded constructor can be created making the invocation even simpler:
EntityManager em = new EntityManager("mycontext");
Compare this last with the original two lines of code and we can immediately see the simplicity.
I simply do not see the benefit of using the repeated code (shown in the first snippet) again and again when the implementation can be hidden away. Isn't good programming about eliminating duplication and reducing string coupling?
Using the Factory pattern but hiding it within the EntityManager class retains the benefits of using the Factory pattern while reducing the string coupling of the Factory and Persistence classes with the EntityManager class.
Doesn't the sample Person class violate the first requirement (i.e. "Must have a no-arg constructor")???
My assumption is that simply adding a no-arg constructor to Person will make the example code correct (no other changes necessary). Can someone verify?