Lets create a simple domain class :
public final class User {
/** The unique identifier. Must be unique among all service events. */
private String id;
/** The name of the particular user. */
private String name;
/** The education of the user. */
private Education educationType;
// here comes constructor and appropriate getters and setters.
}
Next we have to create our enumeration called Education.
For instance :
public enum Education{
/** */
UNIVERSITY,
/** */
COLLEGE,
/** */
SCHOOL
}
A now comes the trick. With help of my colleagues I found class created by Emmanuel Bernard which is the enum type wrapper. Here it is :
public class EnumType
/** */
private static Log log = LogFactory.getLog(EnumType.class);
/** */
private static final boolean IS_TRACE_ENABLED;
static {
//cache this, because it was a significant performance cost
IS_TRACE_ENABLED = LogFactory.getLog(StringHelper.qualifier(Type.class.getName())).isTraceEnabled();
}
public static final String ENUM = "enumClass";
public static final String SCHEMA = "schema";
public static final String CATALOG = "catalog";
public static final String TABLE = "table";
public static final String COLUMN = "column";
public static final String TYPE = "type";
private static Map
private Class
// private int sqlType = Types.INTEGER; // enums will be mapped in bd as integer.
private int sqlType = Types.VARCHAR; // enums will be mapped in bd as varchar.
protected EnumType(final Class
this.enumClass = c;
}
public int[] sqlTypes() {
return new int[]{sqlType};
}
public Class returnedClass() {
return enumClass;
}
public boolean equals(final Object x, final Object y) throws HibernateException {
return x == y;
}
public int hashCode(final Object x) throws HibernateException {
return x == null ? 0 : x.hashCode();
}
public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws HibernateException, SQLException {
final Object object = rs.getObject(names[0]);
if (rs.wasNull()) {
if (IS_TRACE_ENABLED) {
log.debug("Returning null as column " + names[0]);
}
return null;
}
if (object instanceof Number) {
Object[] values = enumValues.get(enumClass);
if (values == null) {
try {
final Method method = enumClass.getDeclaredMethod("values", new Class[0]);
values = (Object[]) method.invoke(null, new Object[0]);
enumValues.put(enumClass, values);
}
catch (Exception e) {
throw new HibernateException("Error while accessing enum.values(): " + enumClass, e);
}
}
final int ordinal = ((Number) object).intValue();
if (ordinal <>= values.length) {
throw new IllegalArgumentException("Unknown ordinal value for enum " + enumClass + ": " + ordinal);
}
if (IS_TRACE_ENABLED) {
log.debug("Returning '" + ordinal + "' as column " + names[0]);
}
return values[ordinal];
} else {
final String name = (String) object;
if (IS_TRACE_ENABLED) {
log.debug("Returning '" + name + "' as column " + names[0]);
}
try {
return Enum.valueOf(enumClass, name);
}
catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("Unknown name value for enum " + enumClass + ": " + name, iae);
}
}
}
public void nullSafeSet(final PreparedStatement st, final Object value, final int index) throws HibernateException, SQLException {
//if (!guessed) guessType( st, index );
if (value == null) {
if (IS_TRACE_ENABLED) log.debug("Binding null to parameter: " + index);
st.setNull(index, sqlType);
} else {
final boolean isOrdinal = isOrdinal(sqlType);
if (isOrdinal) {
final int ordinal = ((Enum) value).ordinal();
if (IS_TRACE_ENABLED) {
log.debug("Binding '" + ordinal + "' to parameter: " + index);
}
st.setObject(index, new Integer(ordinal), sqlType);
} else {
final String enumString = ((Enum) value).name();
if (IS_TRACE_ENABLED) {
log.debug("Binding '" + enumString + "' to parameter: " + index);
}
st.setObject(index, enumString, sqlType);
}
}
}
private boolean isOrdinal(final int paramType) {
switch (paramType) {
case Types.INTEGER:
case Types.NUMERIC:
case Types.SMALLINT:
case Types.TINYINT:
case Types.BIGINT:
case Types.DECIMAL: //for Oracle Driver
case Types.DOUBLE: //for Oracle Driver
case Types.FLOAT: //for Oracle Driver
return true;
case Types.CHAR:
case Types.LONGVARCHAR:
case Types.VARCHAR:
return false;
default:
throw new HibernateException("Unable to persist an Enum in a column of SQL Type: " + paramType);
}
}
public Object deepCopy(final Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(final Object value) throws HibernateException {
return (Serializable) value;
}
public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
return cached;
}
public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
return original;
}
}
Now we need to create a class which will be mapped to bd from one side and will wrap our Education enum from the other. Let's call it EducationEnumType :
public final class EducationEnumType extends EnumType
/* ((( Constructors ))) */
/**
/*
*/
public EducationEnumType() {
super(Education.class);
}
}
We are almost finished. All is left is main part of our User.hbm.xml file : we need to create a property called "education" with type of EducationEnumType (NOT Education!).
1 comment:
ыы, Тарас, да ты фанат)))
Post a Comment