Book Review: Core J2EE Design Patterns 2nd edition

Core J2EE Design Patterns

I read the Core J2EE Design Patterns 2nd edition in July 2005. Below I have written a review for this important book.

Core J2EE Design Patterns is one of the most important books on the traditional J2EE application architecture. If you are programming J2EE systems that are heavily based on EJB 2.x then this book is a must read for you. On the other hand if you are programming J2EE (without EJB :-)) with more lightweight tools, like Spring, don’t rush to go without considering to read this book. This book, no matter which technology you use to implement enterprise applications provides good information on object oriented design and layering.

Of course, as many people have said before, a lot of the core J2EE design patterns are not really patterns but they just provide ways to overcome several limitations in some of the J2EE technologies. Examples of “pseudo-patterns” include Composite Entity and Data Transfer Object which try to address some limitations of the EJB Entity Beans. I believe that the reader can also learn a lot from these “pseudo-patterns”. For example the Data Transfer Object can be seen as a way to decouple two layers or as a more general pattern for distributed computing where you aggregate all the information that you want to pass between the nodes in transfer objects and not just as a way with acceptable performance to get multiple fields from an Entity Bean. For example if for some reason you have a physically separated business tier and you use a technology like Hibernate for persistence you will probably need to have a remote facade that will return transfer objects with all the information that you need in the presentation tier in order to avoid any LazyInitializationException exceptions. I find almost everything in the book useful and educative.

For me a book on design patterns is useful if it has lots of code to illustrate how the patterns can be implemented. The Core J2EE Design Patterns not only provides implementations for all the patterns but also provides and analyzes various implementation strategies. You can see multiple ways to implements most of the patterns, learn the trade-offs of each implementation strategy and also get a deeper understanding of the various J2EE technologies.

The UML diagrams in the book are very good and very helpful since they help you visualize the interactions in the design pattern and you better understand the responsibilities of the participant objects.

I’d like to note two things that are specific to the second edition. First the existence of Web Service Broker, a pattern on how to implement web services in J2EE 1.4, tells us the important role of web services in the J2EE 1.4 update. Second the existence of Business Object tells us that the procedural style of EJB applications made J2EE programmers forget the basics of object oriented programming. You cannot create a rich in behavior domain model with Entity Beans cause they don’t support inheritance and they are not reentrant (if Entity Bean “A” calls Entity Bean “B” then in the same call stack B cannot call back to A). So J2EE programmers implemented all the business logic inside a service layer (with Session Beans), with anemic domain models using Entity Beans. A service layer can be good for things like transaction management, security and other infrastructure services but when you have complex business logic and an anemic domain model you can easily end up with lots of duplicate code. The Business Object is a back to the basics design pattern that acknowledges the importance of rich in behavior domain models.

I would also like to comment on the Composite Entity design pattern. I have very limited knowledge of Entity Beans. I have used Entity Beans in only one project. Most of the projects that I worked on were using Hibernate or JDBC. While reading this pattern I felt very strange since it is very awkward for me to program with Entity Beans. I believe that if you have an exposure to tools like Hibernate and you go back to implement persistence using Entity Beans you are continuously asking yourself “Why things have to be so hard to do and so restrictive?”. I am so glad to see the new EJB 3.0 Entity Beans specification, things are so much better now.

On the other hand, the Domain Store is a welcomed addition to the J2EE patterns. This pattern provides a good explanation for the generic POJO persistence frameworks like Hibernate, JDO and EJB 3.0 (JSR 220).

For me, the Core J2EE Design Patterns 2nd edition was a very pleasant reading since I expanded my knowledge of J2EE and also cleared some things in my mind. I was aware of most of the patterns in this book but reading them from this book made them more clear in my mind. From my experience a lot of J2EE programmers do not really understand most of the core J2EE design patterns and misuse them.

My conclusion for Core J2EE Design Patterns 2nd edition is that it is a very well written book that is a must read for every J2EE developer since not only does it provide valuable information about programming J2EE applications with the traditional architecture but it also defines a widely used vocabulary for common J2EE patterns and idioms.

Implementing Hibernate DAOs

Christian Bauer at the Hibernate team blog has written an improved version of the DAOs of the Caveat Emptor application of the Hibernate in Action book. This new versions will probably be included in the second edition of the book. The new DAOs are implemented in Java 5 using generics and other Java 5 features. Christian Bauer has created a common abstract DAO class, the GenericHibernateDAO, that makes implementing new DAOs easier and removes the code duplication found in the previous versions of the DAOs. I believe that if you plan to use Hibernate with Java 5 you should read his post since it provides a very good starting point for implementing DAOs with generics.

If you are using Hibernate in Java 2 and you want to reuse code from the current version of the CaveatEmptor application you can make a small refactoring to the DAO classes and introduce a common abstract DAO class that will make implementing DAOs easier and will remove much of the duplicate code found in the current implementation of the DAOs.

This refactoring is based on the observation that a lot of the Hibernate operations take the java.lang.Class object of the mapped class as an argument. By introducing a java.lang.Class field (mappedClass) in an abstract DAO class (AbstractDAO) we can move there all the operations of the concrete DAOs of theCaveat Emptor application. With this refactoring of course we assume that we will have a one-to-one mapping between our mapped classes and our DAO classes.

Below I have listed a possible implementation of the abstract DAO and also an implementation of the UserDAO so you can see the code that is removed from the concrete DAOs. The below code is heavily based on the original implementation of Christian Bauer.

// The below code is based on the DAO implementation of
// the Caveat Emptor application of the Hibernate project
// see: http://caveatemptor.hibernate.org
import java.io.Serializable;
import java.util.Collection;

import net.sf.hibernate.Criteria;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.LockMode;
import net.sf.hibernate.Session;
import net.sf.hibernate.expression.Example;

import org.hibernate.auction.exceptions.InfrastructureException;
import org.hibernate.auction.persistence.HibernateUtil;

public class AbstractDAO {

  private Class mappedClass;

  public AbstractDAO(Class c) {
    mappedClass = c;
    HibernateUtil.beginTransaction();
  }

  protected Object getById(Long id, boolean lock) throws InfrastructureException {
    Session session = HibernateUtil.getSession();
    Object object = null;
    try {
      if (lock) {
        object = session.load(mappedClass, id, LockMode.UPGRADE);
      } else {
        object = session.load(mappedClass, id);
      }
    }  catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return object;
  }

  public Collection findAll() throws InfrastructureException {
    Collection objects;
    try {
      objects = HibernateUtil.getSession().createCriteria(mappedClass).list();
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return objects;
  }

  public Collection findByExample(Object example) throws InfrastructureException {
    Collection users;
    try {
      Criteria crit = HibernateUtil.getSession().createCriteria(mappedClass);
      users = crit.add(Example.create(example)).list();
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return users;
  }

  public void makePersistent(Object o) throws InfrastructureException {
    try {
      HibernateUtil.getSession().saveOrUpdate(o);
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  public void makeTransient(Object o) throws InfrastructureException {
    try {
      HibernateUtil.getSession().delete(o);
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  public Class getMappedClass() {
    return mappedClass;
  }
}


import org.hibernate.auction.exceptions.InfrastructureException;
import org.hibernate.auction.model.User;

public class UserDAO extends AbstractDAO {

  public UserDAO() {
    // Pass the class of the DAO to the parent
    super(User.class);
  }

  // Provide a type safe way to get a User object
  // without a cast from the user of the api.
  public User getUserById(Long id, boolean lock) throws InfrastructureException {
    return (User) getById(id, lock);
  }
}

Caching in Service Locator implementations

Here you can find an article by Bobby Woolf that describes why caching inside a Service Locator in J2EE 1.3 applications may have unexpected behavior.

The article also provides a nice explanation of the EJB resource reference mechanism.

Update (19/9/2005):

BTW this is why the Adventure Builder (the sample application developed by SUN for J2EE 1.4) has two implementations for the Service Locator design pattern.

The first implementation is for the EJB tier and does not have caching to avoid the problem explained in the article.

The second implementation is for the web tier and uses caching since resource references in the web tier are the per web application and it is safe to cache them in a static variable.

Refactoring from Template Method to Strategy can reduce code duplication in unit tests

Ivan Moore has a great post “Replacing Inheritance with Composition” at his blog, that explains how when you refactor your code from using Template Method to using Strategy can reduce the code duplication in your unit tests and also make your tests simpler.

Both patterns, template method and strategy, try to solve the same problem. Both patterns allow to separate a “high level” algorithm from other algorithms that vary.

The template method design pattern is class based. This pattern has an abstract class that defines the high level algorithm. The abstract class has a set of abstract methods that provide hooks for the extending classes (concrete classes)to implement a specific algorithm.

In template method the high level algorithm is independent of the specific algorithms. On the other hand the specific algorithms (the concrete classes) depend on the abstract class because they extend it and cannot be used and tested without it.

So since the tests of the concrete classes also test the high level algorithm (the code in the abstract class), which is the same for all the concrete classes it is logical for these test to have code duplication. Also since the tests test both the high level algorithm and a specific algorithm they are more complex.

The strategy design pattern is object based. In strategy we have a class (context) that implements the high level algorithm. This class delegates the details (algorithms that vary) to an interface (strategy interface). To implement a specific algorithm you implement the strategy interface (concrete strategies).

In the strategy the high level algorithm is independent of the specific algorithms. Also the specific algorithms do not depend on the high level algorithm, they depend only on the strategy interface. So the they can be used and tested without the context class.

The test of the strategy code are different. Since the context class is not abstract and only depends on an interface (the strategy interface) the context class can be tested in isolation from the concrete strategies using a mock object. This makes the testing code simpler.

The concrete strategies can be tested independently of the context object (because they only depend on the strategy interface) so their tests are simpler and do not have the code duplication that appears in the tests of the concrete classes at the template method implementation.

To make the above more clear read Ivan Moore‘s article that I mentioned at the beginning of this post. You may also want to read this article by Robert C. Martin at java.net about Strategy and Template Method.