Monday, January 19, 2015

Customizing ENUM in Hibernate


We create the GenericEnumUserType class as follows and use it like this in *.hbm.xml

<property name="responseCode" column="RESPONSE_CODE">
   <type name="net.mycompany.tps.domain.GenericEnumUserType">
    <param name="enumClass">net.mycompany.tps.domain.ExternalResponseCodeEnum</param>
   </type>
  </property>
Here is the net.mycompany.tps.domain.ExternalResponseCodeEnum NOTE the parseId method has to be a static
public enum ExternalResponseCodeEnum {
  ercNotSet(-1),
     ercInvalidCard(101),
     ercOTBDeclined(200),
     ercBlockedCard (210),
     ercBlockedANI(215),
     ercChargeback(220),
     ercBlockedRISK(222),
     ercExceededRiskParameters(230),
     ercCCWDeclined(271),
     ercFirstTimeCaller(280),
     ercSaleDeclined(300),
     ercOTBApproved(400),
     ercCCWTimeoutO(401),
     ercPositiveData(410),
     ercCCWApproved(421),
     ercSaleApproved(500),
     ercCCWTimeoutS(501);
     private int externalResponseCode;

    public static final Map lookupExternalResponseCodeEnum = new HashMap();

    static {
         //Create reverse lookup hash map 
         for(ExternalResponseCodeEnum d : ExternalResponseCodeEnum.values())
             lookupExternalResponseCodeEnum.put(d.getId(), d);
  }
  //constructor
  private ExternalResponseCodeEnum(int code) {
   this.externalResponseCode
   = code;
  }
  public int getId() {
   return externalResponseCode;
  }
  public static int parseId(int id) {
   return "set up the reverse lookup of enum based on id"
  }
}

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.TypeResolver;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;


public class GenericEnumUserType implements UserType, ParameterizedType {

    private Class  enumClass;

    private Class  identifierType;

    private Method identifierMethod;

    private Method valueOfMethod;

    private static final String defaultIdentifierMethodName = "getId";

    private static final String defaultValueOfMethodName = "parseId";

    private AbstractSingleColumnStandardBasicType type;

    private int[] sqlTypes;

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

        String identifierMethodName =
                parameters.getProperty("identifierMethod",
                        defaultIdentifierMethodName);

        try {
            identifierMethod =
                    enumClass.getMethod(identifierMethodName, new Class[0]);
            identifierType = identifierMethod.getReturnType();
        } catch (Exception exception) {
            throw new HibernateException("Failed to optain identifier method",
                    exception);
        }

        TypeResolver tr = new TypeResolver();
        type =
                (AbstractSingleColumnStandardBasicType) tr.basic(identifierType
                        .getName());
        if (type == null) {
            throw new HibernateException("Unsupported identifier type "
                    + identifierType.getName());
        }
        sqlTypes = new int[] {type.sqlType()};

        String valueOfMethodName = parameters.getProperty("valueOfMethod",
                defaultValueOfMethodName);
        try {
            valueOfMethod = enumClass.getMethod(valueOfMethodName,
                            new Class[] {identifierType});
        } catch (Exception exception) {
            throw new HibernateException("Failed to optain valueOf method",
                    exception);
        }
    }

    @Override
    public Class returnedClass() {
        return enumClass;
    }

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        Object identifier = type.get(rs, names[0], null);
        if (identifier == null) {
            return null;
        }

        if (valueOfMethod == null) {

        }

        try {
            return valueOfMethod.invoke(enumClass, new Object[] {identifier});
        } catch (Exception exception) {
            throw new HibernateException(
                    "Exception while invoking valueOfMethod of enumeration class: ",
                    exception);
        }
    }

    public void nullSafeSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {
        try {
            Object identifier =
                    value != null ? identifierMethod.invoke(value,
                            new Object[0]) : null;
            st.setObject(index, identifier);
        } catch (Exception exception) {
            throw new HibernateException(
                    "Exception while invoking identifierMethod of enumeration class: ",
                    exception);

        }
    }

    @Override
    public int[] sqlTypes() {
        return sqlTypes;
    }

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

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

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

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

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

    public boolean isMutable() {
        return false;
    }

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

 @Override
 public Object nullSafeGet(ResultSet arg0, String[] arg1,
   SessionImplementor arg2, Object arg3) throws HibernateException,
   SQLException {
  // TODO Auto-generated method stub
  return null;
 }

 @Override
 public void nullSafeSet(PreparedStatement arg0, Object arg1, int arg2,
   SessionImplementor arg3) throws HibernateException, SQLException {
  // TODO Auto-generated method stub
  nullSafeSet(arg0, arg1, arg2);
 }
}

No comments:

Post a Comment