After reading the material about Java 1.5 enum and Hibernate UserType
http://www.hibernate.org/272.html I did the following to use that concepts in java 1.4.
I defined an abstract enumeration class:
Code:
public abstract class AbstractEnum implements Serializable {
private String id;
private transient String value;
/**
* @param id
* @param value
*/
protected AbstractEnum(String id, String value) {
this.id = id;
this.value = value;
}
/**
* @return Returns the id.
*/
public String getId() {
return id;
}
/**
* @return Returns the value.
*/
public String getValue() {
return value;
}
public boolean equals(Object other) {
return this == other;
}
public int hashCode() {
return System.identityHashCode(id);
}
public String toString() {
return value;
}
}
and its implementation:
Code:
public class NumberEnum extends AbstractEnum {
public static final String ONE = "1";
public static final String TWO = "2";
public static final NumberEnum ONE_LITERAL = new NumberEnum(ONE, "One");
public static final NumberEnum TWO_LITERAL = new NumberEnum(TWO, "Two");
/**
* @param id
* @param value
*/
private NumberEnum(String id, String value) {
super(id, value);
}
public static NumberEnum fromString(String id) {
if (ONE.equals(id)) {
return ONE_LITERAL;
} else if (TWO.equals(id)) {
return TWO_LITERAL;
} else {
return null;
}
}
private Object resolveObject() {
return fromString(getId());
}
}
then, I defined the EnumUserType class as explained in the article:
Code:
public class EnumUserType implements EnhancedUserType, ParameterizedType {
private Class enumClass;
private Method fromString;
/* (non-Javadoc)
* @see org.hibernate.usertype.EnhancedUserType#objectToSQLString(java.lang.Object)
*/
public String objectToSQLString(Object value) {
return '\'' + idOf(value) + '\'';
}
/* (non-Javadoc)
* @see org.hibernate.usertype.EnhancedUserType#toXMLString(java.lang.Object)
*/
public String toXMLString(Object value) {
return idOf(value);
}
/* (non-Javadoc)
* @see org.hibernate.usertype.EnhancedUserType#fromXMLString(java.lang.String)
*/
public Object fromXMLString(String xmlValue) {
return valueOf(xmlValue);
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#sqlTypes()
*/
public int[] sqlTypes() {
return new int[] { Types.VARCHAR };
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#returnedClass()
*/
public Class returnedClass() {
return enumClass;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
*/
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
*/
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String name = rs.getString( names[0] );
return rs.wasNull() ? null : valueOf(name);
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.VARCHAR);
} else {
st.setString(index, idOf(value));
}
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object value) throws HibernateException {
return value;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#isMutable()
*/
public boolean isMutable() {
return false;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
*/
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable)value;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
*/
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
*/
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
/* (non-Javadoc)
* @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties)
*/
public void setParameterValues(Properties parameters) {
String enumClassName = parameters.getProperty("enumClassName");
try {
enumClass = Class.forName(enumClassName);
fromString = enumClass.getMethod("fromString", new Class[] {String.class});
if (!AbstractEnum.class.isAssignableFrom(enumClass)) {
throw new HibernateException("Enum class <" + enumClassName + "> does not extend AbstractEnum class.");
}
} catch (ClassNotFoundException cnfe) {
throw new HibernateException("Enum class <" + enumClassName + "> not found: ", cnfe);
} catch (NoSuchMethodException nsme) {
throw new HibernateException("Enum class <" + enumClassName + "> does not contain formString method: ", nsme);
}
try {
enumClass.getDeclaredMethod("resolveObject", new Class[0]);
} catch (NoSuchMethodException nsme) {
throw new HibernateException("Enum class <" + enumClassName + "> does not contain resolveObject method: ");
}
}
private String idOf(Object value) {
return ((AbstractEnum)value).getId();
}
private Object valueOf(String id) {
try {
return fromString.invoke(null, new Object[] {id});
} catch (IllegalAccessException e) {
throw new HibernateException("Illegal access to method fromString from class <" + enumClass.getName() + ">: ", e);
} catch (InvocationTargetException e) {
throw new HibernateException("Could not invoke method fromString from class <" + enumClass.getName() + ">: ", e);
}
}
}
I used these on this sample hbm file:
Code:
<?xml version="1.0" encoding="ASCII"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.foo.bar.test">
<class name="TestEnum" table="testEnum">
<id column="id" name="id" type="long">
<generator class="native"/>
</id>
<property column="test_enum" length="1" name="testEnum">
<type name="com.previnet.hibernate.usertypes.EnumUserType">
<param name="enumClassName">com.foo.bar.test.NumberEnum</param>
</type>
</property>
</class>
</hibernate-mapping>
Generating the java code with the Hibernate Tools Eclipse plugin I obtained the following:
Code:
public class TestEnum implements java.io.Serializable {
// Fields
private Long id;
private NumberEnum testEnum;
// Constructors
/** default constructor */
public TestEnum() {
}
/** constructor with id */
public TestEnum(Long id) {
this.id = id;
}
// Property accessors
/**
*
*/
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
/**
*
*/
public NumberEnum getTestEnum() {
return this.testEnum;
}
public void setTestEnum(NumberEnum testEnum) {
this.testEnum = testEnum;
}
}
I hope this can help somebody.
Cheers
Adriano