用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:
[url]http://community.jboss.org/wiki/Java5StringValuedEnumUserType[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>