Friday, September 01, 2006

 

Enum Type in Hibernate Mapping

參考這篇「Java 5 EnumUserType」文章
就直接用昨天Generic CRUD DAO程式來改吧!

EnumUserType.java

以這個EnumUserType class來轉接Enum Type

package util;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.ParameterizedType;

/**
 * @author Gavin King
 */
public class EnumUserType implements EnhancedUserType, ParameterizedType {

   private Class<Enum> enumClass;

   public void setParameterValues(Properties parameters) {
      String enumClassName = parameters.getProperty("enumClassName");
      try {
         enumClass = (Class<Enum>) Class.forName(enumClassName);
      } catch (ClassNotFoundException cnfe) {
         throw new HibernateException("Enum class not found", cnfe);
      }
   }

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

   public Object deepCopy(Object value) throws HibernateException {
      return value;
   }

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

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

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

   public boolean isMutable() {
      return false;
   }

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

   public void nullSafeSet(PreparedStatement st, Object value, int index)
         throws HibernateException, SQLException {
      if (value == null) {
         st.setNull(index, Types.VARCHAR);
      } else {
         st.setString(index, ((Enum) value).name());
      }
   }

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

   public Class returnedClass() {
      return enumClass;
   }

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

   public Object fromXMLString(String xmlValue) {
      return Enum.valueOf(enumClass, xmlValue);
   }

   public String objectToSQLString(Object value) {
      return '\'' + ((Enum) value).name() + '\'';
   }

   public String toXMLString(Object value) {
      return ((Enum) value).name();
   }

}

Person.java

加入一個Gender enum type

package genericdaotest.domain;

import java.io.Serializable;

public class Person implements Serializable {
   private Long id;

   private String name;

   private Gender gender;

   private Integer weight;

   public Person(String name, Gender gender, Integer weight) {
      this.name = name;
      this.gender = gender;
      this.weight = weight;
   }

   // Default constructor needed by Hibernate
   protected Person() {
   }

   public Long getId() {
      return id;
   }

   private void setId(Long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   private void setName(String name) {
      this.name = name;
   }

   public Gender getGender() {
      return gender;
   }

   public void setGender(Gender gender) {
      this.gender = gender;
   }

   public Integer getWeight() {
      return weight;
   }

   public void setWeight(Integer weight) {
      this.weight = weight;
   }
}

Gender.java

package genericdaotest.domain;

public enum Gender {
   MALE, FEMALE
}

Person.hbm.xml

修改mapping檔

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="genericdaotest.domain">
   <class name="Person">
      <id name="id">
         <generator class="native"></generator>
      </id>
      <property name="name" update="false" />
      <property name="gender">
         <type name="util.EnumUserType">
            <param name="enumClassName">
               genericdaotest.domain.Gender
            </param>
         </type>
      </property>
      <property name="weight" />
   </class>
</hibernate-mapping>

PersonDaoTest.java

修改test case

package genericdaotest;

import genericdao.GenericDao;
import genericdaotest.domain.Gender;
import genericdaotest.domain.Person;
import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * Simple test of the PersonDao
 */
public class PersonDaoTest extends TestCase {
   private ApplicationContext factory;

   public PersonDaoTest(String s) {
      super(s);
      factory = new ClassPathXmlApplicationContext("my-test.xml");
   }

   public void testCrud() throws Exception {
      // Create
      GenericDao personDao = (GenericDao) factory.getBean("personDao");
      Person createPerson = new Person("Mellqvist", Gender.MALE, 88);
      personDao.create(createPerson);
      assertNotNull(createPerson.getId());
      Long id = createPerson.getId();

      restartSession();

      // Read
      Person foundPerson = (Person) personDao.read(id);
      assertEquals(createPerson.getGender(), foundPerson.getGender());

      restartSession();

      // Update
      Gender updateGender = Gender.FEMALE;
      foundPerson.setGender(updateGender);
      personDao.update(foundPerson);
      Person updatedPerson = (Person) personDao.read(id);
      assertEquals(updateGender, updatedPerson.getGender());
      restartSession();

      // Delete
      personDao.delete(updatedPerson);
      restartSession();
      assertNull(personDao.read(id));
   }

   protected void setUp() throws Exception {
      openSession();
   }

   protected void tearDown() throws Exception {
      closeSession();
   }

   private void openSession() {
      SessionFactory sessionFactory = getSessionFactory();
      Session session = SessionFactoryUtils.getSession(sessionFactory, true);
      TransactionSynchronizationManager.bindResource(sessionFactory,
            new SessionHolder(session));
   }

   private void closeSession() {
      SessionFactory sessionFactory = getSessionFactory();
      SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
            .unbindResource(sessionFactory);
      sessionHolder.getSession().flush();
      sessionHolder.getSession().close();
      SessionFactoryUtils.releaseSession(sessionHolder.getSession(),
            sessionFactory);
   }

   private void restartSession() {
      closeSession();
      openSession();
   }

   private SessionFactory getSessionFactory() {
      return (SessionFactory) factory.getBean("sessionFactory");
   }
}