首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

用Hibernate照射INT字段到枚举类型

2012-11-12 
用Hibernate映射INT字段到枚举类型当实体中包含类似XxxxType字段时,为了性能上的考虑,一般数据库里的字段

用Hibernate映射INT字段到枚举类型
当实体中包含类似XxxxType字段时,为了性能上的考虑,一般数据库里的字段类型为TINYINT或INT。而自从Java提供枚举类型以后,在Java代码中使用枚举类型来表示这种变量会更好。于是自然要在Hibernate里把TINYINT字段映射到枚举类型。我对Hibernate也不熟,网上找了一下发现内容很少,而且能找到的大多是把枚举类型映射到字符串类型的字段。挺奇怪的,难道大家还是在用定义一堆final static int的常量来表示XxxxType么?

不管怎样,只好根据找到的最靠谱的代码再修改了一下。最终效果还不错。Bean的写法如下,枚举类型需要实现IntegerValuedEnum接口即可。

public class Test {    public enum TestType implements IntegerValuedEnum {        Type1(1), Type2(2), Type3(3);                private final int code;        private TestType(int code) {            this.code = code;        }        @Override        public int getCode() {            return code;        }    }        private int id;    private TestType testType;    // Other setters and getters}


在映射xml文件中如下配置testType:

<property name="testType" column="TEST_TYPE">    <type name="com.buzzinate.bshare.hibernate.IntegerValuedEnumType">        <param name="enum">com.buzzinate.bshare.beans.Test$TestType</param>    </type></property> 


以下是实现代码。

IntegerValuedEnum接口:
public interface IntegerValuedEnum {        int getCode();}


IntegerValuedEnumReflect类
/** * Utility class designed to inspect IntegerValuedEnums. */public final class IntegerValuedEnumReflect {    /**     * Don't let anyone instantiate this class.     *      * @throws UnsupportedOperationException     *             Always.     */    private IntegerValuedEnumReflect() {        throw new UnsupportedOperationException("This class must not be instanciated.");    }    /**     * All Enum constants (instances) declared in the specified class.     *      * @param enumClass        Class to reflect     * @return Array of all declared EnumConstants (instances).     */    private static <T extends Enum> T[] getValues(Class<T> enumClass) {        return enumClass.getEnumConstants();    }    /**     * All possible string values of the string valued enum.     *      * @param enumClass        Class to reflect.     * @return Available integer values.     */    public static <T extends Enum & IntegerValuedEnum> int[] getStringValues(            Class<T> enumClass) {        T[] values = getValues(enumClass);        int[] result = new int[values.length];        for (int i = 0; i < values.length; i++) {            result[i] = values[i].getCode();        }        return result;    }    /**     * Name of the enum instance which hold the respecified string value. If     * value has duplicate enum instances than returns the first occurrence.     *      * @param enumClass        Class to inspect.     * @param value            The int value.     * @return name of the enum instance.     */    public static <T extends Enum & IntegerValuedEnum> String getNameFromValue(            Class<T> enumClass, int value) {        T[] values = getValues(enumClass);        for (int i = 0; i < values.length; i++) {            if (values[i].getCode() == value) {                return values[i].name();            }        }        return "";    }}


IntegerValuedEnumType类,也是最主要的类,实现了Hibernate的UserType接口。
public class IntegerValuedEnumType<T extends Enum & IntegerValuedEnum> implements        EnhancedUserType, ParameterizedType {    /**     * Enum class for this particular user type.     */    private Class<T> enumClass;    /**     * Value to use if null.     */    private Integer defaultValue;    public IntegerValuedEnumType() { }    public void setParameterValues(Properties parameters) {        String enumClassName = parameters.getProperty("enum");        try {            enumClass = (Class<T>) Class.forName(enumClassName).asSubclass(Enum.class)                    .asSubclass(IntegerValuedEnum.class);         } catch (ClassNotFoundException e) {            throw new HibernateException("Enum class not found", e);        }                String defaultValueStr = parameters.getProperty("defaultValue");        if (defaultValueStr != null && !defaultValueStr.isEmpty()) {            try {                setDefaultValue(Integer.parseInt(defaultValueStr));            } catch (NumberFormatException e) {                throw new HibernateException("Invalid default value", e);            }        }    }    public Integer getDefaultValue() {        return defaultValue;    }    public void setDefaultValue(Integer defaultValue) {        this.defaultValue = defaultValue;    }    /**     * The class returned by <tt>nullSafeGet()</tt>.     *      * @return Class     */    public Class returnedClass() {        return enumClass;    }    public int[] sqlTypes() {        return new int[] { Types.TINYINT };    }    public boolean isMutable() {        return false;    }    /**     * Retrieve an instance of the mapped class from a JDBC resultset.     * Implementors should handle possibility of null values.     *      * @param rs         a JDBC result set     * @param names     the column names     * @param owner     the containing entity     * @return Object     * @throws HibernateException     * @throws SQLException     */    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)        throws SQLException {                Integer value = rs.getInt(names[0]);        if (value == null) {            value = getDefaultValue();            if (value == null) { // no default value                return null;            }        }        String name = IntegerValuedEnumReflect.getNameFromValue(enumClass, value);        Object res = rs.wasNull() ? null : Enum.valueOf(enumClass, name);        return res;    }    /**     * Write an instance of the mapped class to a prepared statement.     * Implementors should handle possibility of null values. A multi-column     * type should be written to parameters starting from <tt>index</tt>.     *      * @param st        a JDBC prepared statement     * @param value        the object to write     * @param index        statement parameter index     * @throws HibernateException     * @throws SQLException     */    public void nullSafeSet(PreparedStatement st, Object value, int index)        throws SQLException {                if (value == null) {            st.setNull(index, Types.TINYINT);        } else {            st.setInt(index, ((T) value).getCode());        }    }    public Object assemble(Serializable cached, Object owner) {        return cached;    }    public Serializable disassemble(Object value) {        return (Enum) value;    }    public Object deepCopy(Object value) {        return value;    }    public boolean equals(Object x, Object y) {        return x == y;    }    public int hashCode(Object x) {        return x.hashCode();    }    public Object replace(Object original, Object target, Object owner) {        return original;    }    public String objectToSQLString(Object value) {        return '\'' + String.valueOf(((T) value).getCode()) + '\'';    }    public String toXMLString(Object value) {        return String.valueOf(((T) value).getCode());    }    public Object fromXMLString(String xmlValue) {        Integer value = Integer.parseInt(xmlValue);        String name = IntegerValuedEnumReflect.getNameFromValue(enumClass, value);        return Enum.valueOf(enumClass, name);    }}




Reference:
http://community.jboss.org/wiki/Java5StringValuedEnumUserType

热点排行