State Pattern Persistence with Hibernate

In my software development job, I do a lot of persistence layer implementation, especially using the Hibernate O/R mapper. I work closely with a clever domain layer programmer who tends to use a lot of design patterns, perhaps because he likes the woman of the cover of Head First Design Patterns.

Sometimes, these design patterns create a bit of a challenge for me in the persistence layer, especially since I always tell my domain layer programmer that I can persist things transparently, without having to muck up his code with persistence layer artifacts.

A case in point is the State pattern. I have now persisted 5 different sets of states so it’s no longer a challenge. However, it took me a little while to figure how to do it. Naturally, I started by checking out Hibernate’s forums but much to my chagrin, I found several people asking the same question but no one offering an answer. Therefore, I will provide an answer in this blog post.

Imagine you have a Customer class, which is playing the “context” role in the design pattern. The customer has a simple state machine with two states: active and inactive. I’ve implemented State pattern persistence in two ways: without an enumeration and with an enumeration. First, here is a sample implementation of the pattern in the domain layer, without using an enumeration:

public interface CustomerState
{
  /**
   * Checks whether the CustomerState is 'Active'.
   * @return true if the CustomerState is 'Active'.
   */
  boolean isActive();

  /**
   * Checks whether the CustomerState is 'Inactive'.
   * @return true if the CustomerState is 'Inactive'.
   */
  boolean isInactive();

  /**
   * Activates the specified Customer.
   * @param customer the Customer being activated.
   */
  void activate(Customer customer);

  /**
   * Deactivates the specified Customer.
   * @param customer the Customer being deactivated.
   */
  void deactivate(Customer customer);
}
/**
* All concrete subclasses of this class are stateless (they have no instance
* variables). Therefore, we have overridden equals and hashCode (see below)
* because any instance of a particular subclass should be considered equal to
* any other instance of that sublcass.
*/
public abstract class AbstractCustomerState implements CustomerState
{
 public static final CustomerState ACTIVE = new CustomerStateActive();
 public static final CustomerState INACTIVE = new CustomerStateInactive();

 public boolean isActive()
 {
   return false;
 }

 public boolean isInactive()
 {
   return false;
 }

 public void activate(Customer customer)
 {
   throw new UnsupportedOperationException();
 }

 public void deactivate(Customer customer)
 {
   throw new UnsupportedOperationException();
 }

 /**
  * Returns true if the Object's class name matches this Object's class name.
  */
 public final boolean equals(Object obj)
 {
   if (this == obj)
   {
     return true;
   }
   if (obj == null)
   {
     return false;
   }
   return getClass().getName().equals(obj.getClass().getName());
 }

 /**
  * Returns the hashCode of the Object's Class name because all instances of
  * this Class are equal.
  */
 public final int hashCode()
 {
   return getClass().getName().hashCode();
 }
}
public class CustomerStateActive extends AbstractCustomerState
{
 public boolean isActive()
 {
   return true;
 }

 public void deactivate(Customer customer)
 {
   // do some checks to make sure it's okay to deactivate this customer
   // ...

   // set the state
   ((AbstractCustomer) customer).setState(AbstractCustomerState.INACTIVE);
 }
}
public class CustomerStateInactive extends AbstractCustomerState
{
 public boolean isInactive()
 {
   return true;
 }

 public void activate(Customer customer)
 {
   // do some checks to make sure it's okay to activate this customer
   // ...

   // set the state
   ((AbstractCustomer) customer).setState(AbstractCustomerState.ACTIVE);
 }
}

Notice in my example that I have made the states stateless. Yes, I realized that a stateless state seems like an oxymoron but it’s true; the above state classes do not have any instance variables. Since they are stateless, any instance of a state is equal to any other instance of that same state. That’s why I overrode the equals() and hashCode() methods. Since the states are stateless, I also created constants for each state (ACTIVE and INACTIVE) in the abstract base class so that we don’t have to keep on instantiating them all over the place.

Anyway, the code above is what the domain layer developer would hand over to me. Then it would be my job to persist it. The first task is to make a Hibernate UserType implementation:

public class CustomerStateUserType implements UserType
{
 public static final int ACTIVE_STATE_DB_VALUE = 1;
 public static final int INACTIVE_STATE_DB_VALUE = 2;

 public int[] sqlTypes()
 {
   return new int[] {Types.INTEGER};
 }

 public Class returnedClass()
 {
   return CustomerState.class;
 }

 public boolean isMutable()
 {
   // CustomerStates are stateless, therefore they are clearly immutable
   return false;
 }

 public Object deepCopy(Object value) throws HibernateException
 {
   // CustomerStates are immutable
   return value;
 }

 public Serializable disassemble(Object value) throws HibernateException
 {
   // CustomerStates are immutable
   return (Serializable) value;
 }

 public Object assemble(Serializable cached, Object owner)
   throws HibernateException
 {
   // CustomerStates are immutable
   return cached;
 }

 public Object replace(Object original, Object target, Object owner)
   throws HibernateException
 {
   // CustomerStates are immutable
   return original;
 }

 public boolean equals(Object x, Object y)
   throws HibernateException
 {
   if (x == y)
   {
     return true;
   }
   if (x == null || y == null)
   {
     return false;
   }
   return x.equals(y);
 }

 public int hashCode(Object x) throws HibernateException
 {
   return x.hashCode();
 }

 public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
   throws HibernateException, SQLException
 {
   final int stateValue = rs.getInt(names[0]);
   if (rs.wasNull())
   {
     return null;
   }

   CustomerState state = null;
   switch (stateValue)
   {
     case ACTIVE_STATE_DB_VALUE:
       state = AbstractCustomerState.ACTIVE;
       break;
     case INACTIVE_STATE_DB_VALUE:
       state = AbstractCustomerState.INACTIVE;
       break;
     default:
       throw new RuntimeException("Unknown CustomerState value ["
         + stateValue + "]");
   }
   return state;
 }

 public void nullSafeSet(PreparedStatement st, Object value, int index)
   throws HibernateException, SQLException
 {
   if (value == null)
   {
     st.setNull(index, Types.INTEGER);
   }
   else
   {
     if (value.equals(AbstractCustomerState.ACTIVE))
     {
       st.setInt(index, ACTIVE_STATE_DB_VALUE);
     }
     else if (value.equals(AbstractCustomerState.INACTIVE))
     {
       st.setInt(index, INACTIVE_STATE_DB_VALUE);
     }
     else
     {
       throw new RuntimeException("Unknown CustomerState [" + value + "]");
     }
   }
 }
}

As you can see, most of the interesting code is in nullSafeGet() and nullSafeSet(), which map the states to an integer column in the database. Next, you need to map it:

<hibernate-mapping>
<class name="Customer" table="customer">
 <property name="state" column="state" type="CustomerStateUserType"
   access="field"/>
 <!-- ...other properties -->
</class>
</hibernate-mapping>

Pretty easy, huh? The only problem with this implementation is that if the domain layer developer subsequently adds another state, I have to modify my UserType to account for the new state. If the domain layer developer forgets to tell me about the new state, it could be awhile before the error is discovered. Of course, one way around this is to make nullSafeGet and nullSafeSet map each state to the state’s class name. For example:

public class CustomerStateUserType implements UserType
{

 public int[] sqlTypes()
 {
   return new int[] {Types.VARCHAR};
 }

 //...other methods

 public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
   throws HibernateException, SQLException
 {
   final String stateValue = rs.getString(names[0]);
   if (rs.wasNull())
   {
     return null;
   }

   CustomerState state = null;

   try
   {
     state = (CustomerState) Class.forName(stateValue).newInstance();
   }
   catch (Exception e)
   {
     throw new RuntimeException("Can't instantiate instance of ["
       + stateValue + "]", e);
   }

   if (!(state instanceof CustomerState))
   {
     throw new RuntimeException("Unknown CustomerState value ["
       + stateValue + "]");
   }

   return state;
 }

 public void nullSafeSet(PreparedStatement st, Object value, int index)
   throws HibernateException, SQLException
 {
   if (value == null)
   {
     st.setNull(index, Types.VARCHAR);
   }
   else
   {
     if (value instanceof AbstractCustomerState)
     {
       st.setString(index, value.getClass().getName());
     }
     else
     {
       throw new RuntimeException("Unknown CustomerState ["
         + value + "]");
     }
   }
 }
}

Of course, the problem with storing the class name in the database column is that it takes up more space than an integer; consider the relative cost of storing a million records with an integer state value versus a value like “com.mycompany.someapp.domain.customer.CustomerStateActive”.

The second style of implementing this pattern involves using an enumeration, specifically Apache’s Jakarta-commons Enum class (of course, you could probably use Java 1.5′s new enum feature too). Here are the relevant domain layer classes:

import org.apache.commons.lang.enums.Enum;

public abstract class AbstractCustomerState extends Enum implements CustomerState
{
 public static final CustomerState ACTIVE = new CustomerStateActive();
 public static final CustomerState INACTIVE = new CustomerStateInactive();

 protected AbstractCustomerState(String name)
 {
   super(name);
 }

 /**
  * Overrides superclass method to allow enums to be subclasses, yet still be
  * part of the same enumeration. This is what allows an enum to play the role
  * of a State in the State design pattern. The Javadoc comments for Enum call
  * this type of Enum a "Functional Enum".
  * @see org.apache.commons.lang.enums.Enum#getEnumClass()
  * @see org.apache.commons.lang.enums.Enum
  */
 public final Class getEnumClass()
 {
   return AbstractCustomerState.class;
 }

 public static AbstractCustomerState getEnum(String name)
 {
   return (AbstractCustomerState) getEnum(
     AbstractCustomerState.class, name);
 }

 public static Map getEnumMap()
 {
   return getEnumMap(AbstractCustomerState.class);
 }

 public static List getEnumList()
 {
   return getEnumList(AbstractCustomerState.class);
 }

 public static Iterator iterator()
 {
   return iterator(AbstractCustomerState.class);
 }

 //----------------start of CustomerState methods---------------------
 public boolean isActive()
 {
   return false;
 }

 public boolean isInactive()
 {
   return false;
 }

 public void activate(Customer customer)
 {
   throw new UnsupportedOperationException();
 }

 public void deactivate(Customer customer)
 {
   throw new UnsupportedOperationException();
 }
}
public class CustomerStateActive extends AbstractCustomerState
{
 CustomerStateActive()
 {
   super("ACTIVE");
 }

 public boolean isActive()
 {
   return true;
 }

 public void deactivate(Customer customer)
 {
   // do some checks to make sure it's okay to deactivate this customer
   // ...

   // set the state
   ((AbstractCustomer) customer).setState(AbstractCustomerState.INACTIVE);
 }
}
public class CustomerStateInactive extends AbstractCustomerState
{
 CustomerStateInactive()
 {
   super("INACTIVE");
 }

 public boolean isInactive()
 {
   return true;
 }

 public void activate(Customer customer)
 {
   // do some checks to make sure it's okay to activate this customer
   // ...

   // set the state
   ((AbstractCustomer) customer).setState(AbstractCustomerState.ACTIVE);
 }
}

There is a tradeoff with this implementation. Notice the extra code at the top of AbstractCustomerState? I must override several methods of the Enum class, as per the “Functional Enums” section of Enum’s JavaDocs. For the UserType, I started by making an abstract base class for all enumerations:

/**
* Maps a org.apache.commons.lang.enums.Enum to a Hibernate type. This
* allows you to persist Enum instances. This class was adapted from an
* example posted in this forum
* thread  and an example on page 210 of "Hibernate in Action" (first
* edition).
*/
public abstract class EnumUserType implements UserType
{
 private Class enumClass;

 public EnumUserType(Class enumClass)
 {
   this.enumClass = enumClass;
 }

 public int[] sqlTypes()
 {
   return new int[] {
     Types.VARCHAR
   };
 }

 public Class returnedClass()
 {
   return enumClass;
 }

 public boolean equals(Object x, Object y) throws HibernateException
 {
   if (x == y)
   {
     return true;
   }

   if (x == null || y == null)
   {
     return false;
   }

   return Hibernate.STRING.isEqual(x, y);
 }

 public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
   throws HibernateException, SQLException
 {
   String value = rs.getString(names[0]);
   return rs.wasNull() ? null : EnumUtils.getEnum(enumClass, value);
 }

 public void nullSafeSet(PreparedStatement st, Object value, int index)
   throws HibernateException, SQLException
 {
   // make sure the received value is of the right type
   if ((value != null) && !returnedClass().isAssignableFrom(value.getClass()))
   {
     throw new IllegalArgumentException("Received value is not a["
       + returnedClass().getName() + "] but [" + value.getClass() + "]");
   }

   if (value != null)
   {
     Enum enum = (Enum) value;

     // convert the enum into its persistence format
     String enumName = enum.getName();

     // set the value into the resultset
     st.setString(index, enumName);
   }
   else
   {
     st.setNull(index, Types.VARCHAR);
   }
 }

 public Object deepCopy(Object value) throws HibernateException
 {
   // Enums are immutable - nothing to be done to deeply clone it
   return value;
 }

 public boolean isMutable()
 {
   // Enums are immutable
   return false;
 }

 public int hashCode(Object object) throws HibernateException
 {
   return object.hashCode();
 }

 public Serializable disassemble(Object value)
   throws HibernateException
 {
   return (Serializable) value;
 }

 public Object assemble(Serializable cached, Object owner)
   throws HibernateException
 {
   return cached;
 }

 public Object replace(Object original, Object target, Object owner)
   throws HibernateException
 {
   return original;
 }
}

Then, I extended that base class to create a CustomerStateUserType.

public class CustomerStateUserType extends EnumUserType
{
 public CustomerStateUserType()
 {
   super(AbstractCustomerState.class);
 }
}

Notice that the derived UserType is a piece of cake to make.

If this tip helped you, please leave me a comment!

Be Sociable, Share!

    5 comments to State Pattern Persistence with Hibernate

    • l0st3d

      hey Joe,

      I found this useful for some work I’d been doing today, so I thought
      I’d leave a comment and say thanks. We were trying to persist a state
      pattern implemented in a stateless way, with an abstract state class
      being extended for multiple states. We have managed to argue our way
      into restructuring the state model as a java 5 Enum that has methods
      the state transition methods implemented like:

      http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

      This appears to be persisted by hibernate as an integer, without the
      need to create a user type, which we felt was a quicker and easier
      solution, as the EJB3 world is all a bit new to most of the
      development team.

    • Joe

      Thanks for dropping by my blog.

      > the EJB3 world is all a bit
      > new to most of the
      > development team

      Hehe, just be thankful they don’t have to learn EJB2!

    • Campbell

      Hi Joe. I too found this a useful piece based on attempting to implement the State Pattern from the book with the nice girl on the cover :O)

      The problem I could not crack was the fact the pattern actually instantiates the states within the entity and passes a ‘this’ reference in to each state constructor.

      You provide an alternative which is to pass the entity reference (e.g. Customer) in to the action method (e.g activate). A nice touch but I wish to retain the original pattern structure since it is cleaner for my requirement: my different states sometimes transition the entity state bit sometimes do not require to do so.

      I cannot see any way to use Hibernate UserType to retain the exact pattern implementation but let me know if you think otherwise.

      Cheers, Cam

    • Anonymous

      org.hibernate.MappingException: Could not determine type for: OrderStateUserType

      where i have put OrderStateUserType when i have complicate structure?

    • ilizhe

      i got something useful from your blog. thank u

    Leave a Reply

     

     

     

    You can use these HTML tags

    <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>