1 package org.hibernate.type; 3 4 import java.io.Serializable ; 5 import java.lang.reflect.Method ; 6 import java.sql.PreparedStatement ; 7 import java.sql.ResultSet ; 8 import java.sql.SQLException ; 9 import java.sql.Types ; 10 import java.util.HashMap ; 11 import java.util.Map ; 12 import java.util.Properties ; 13 14 import org.apache.commons.logging.Log; 15 import org.apache.commons.logging.LogFactory; 16 import org.hibernate.HibernateException; 17 import org.hibernate.util.StringHelper; 18 import org.hibernate.util.ReflectHelper; 19 import org.hibernate.usertype.ParameterizedType; 20 import org.hibernate.usertype.UserType; 21 22 27 public class EnumType implements UserType, ParameterizedType { 28 private static Log log = LogFactory.getLog(EnumType.class); 30 private static final boolean IS_TRACE_ENABLED; 31 static { 32 IS_TRACE_ENABLED = LogFactory.getLog( StringHelper.qualifier( Type.class.getName() ) ).isTraceEnabled(); 34 } 35 36 public static final String ENUM = "enumClass"; 37 public static final String SCHEMA = "schema"; 38 public static final String CATALOG = "catalog"; 39 public static final String TABLE = "table"; 40 public static final String COLUMN = "column"; 41 42 private static Map <Class ,Object []> enumValues = new HashMap <Class , Object []>(); 43 44 private Class <? extends Enum > enumClass; 45 private String column; 46 private String table; 47 private String catalog; 48 private String schema; 49 private boolean guessed = false; 50 private int sqlType = Types.INTEGER; 52 public int[] sqlTypes() { 53 return new int[] { sqlType }; 54 } 55 56 public Class returnedClass() { 57 return enumClass; 58 } 59 60 public boolean equals(Object x, Object y) throws HibernateException { 61 return x == y; 62 } 63 64 public int hashCode(Object x) throws HibernateException { 65 return x.hashCode(); 66 } 67 68 public Object nullSafeGet(ResultSet rs, String [] names, Object owner) throws HibernateException, SQLException { 69 Object object = rs.getObject( names[0] ); 70 if ( rs.wasNull() ) { 71 if ( IS_TRACE_ENABLED ) { 72 log.debug("Returning null as column " + names[0]); 73 } 74 return null; 75 } 76 if (object instanceof Number ) { 77 Object [] values = enumValues.get(enumClass); 78 if (values == null) { 79 try { 80 Method method = null; 81 method = enumClass.getDeclaredMethod( "values", new Class [0] ); 82 values = (Object []) method.invoke(null, new Object [0] ); 83 enumValues.put( enumClass, values ); 84 } 85 catch (Exception e) { 86 throw new HibernateException("Error while accessing enum.values(): " + enumClass, e); 87 } 88 } 89 int ordinal = ( (Number ) object ).intValue(); 90 if (ordinal < 0 || ordinal >= values.length) { 91 throw new IllegalArgumentException ("Unknown ordinal value for enum " + enumClass + ": " + ordinal); 92 } 93 if ( IS_TRACE_ENABLED ) { 94 log.debug("Returning '" + ordinal + "' as column " + names[0]); 95 } 96 return values[ordinal]; 97 } 98 else { 99 String name = (String ) object; 100 if ( IS_TRACE_ENABLED ) { 101 log.debug("Returning '" + name + "' as column " + names[0]); 102 } 103 try { 104 return Enum.valueOf(enumClass, name); 105 } 106 catch (IllegalArgumentException iae) { 107 throw new IllegalArgumentException ("Unknown name value for enum " + enumClass + ": " + name, iae); 108 } 109 } 110 } 111 112 public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 113 if (!guessed) guessType( st, index ); 114 if (value == null) { 115 if (IS_TRACE_ENABLED) log.debug("Binding null to parameter: " + index); 116 st.setNull( index, sqlType ); 117 } 118 boolean isOrdinal = isOrdinal(sqlType); 119 if (isOrdinal) { 120 int ordinal = ( (Enum ) value ).ordinal(); 121 if ( IS_TRACE_ENABLED ) { 122 log.debug("Binding '" + ordinal + "' to parameter: " + index); 123 } 124 st.setObject( index, new Integer (ordinal), sqlType ); 125 } 126 else { 127 String enumString = ( (Enum ) value ).name(); 128 if ( IS_TRACE_ENABLED ) { 129 log.debug("Binding '" + enumString + "' to parameter: " + index); 130 } 131 st.setObject( index, enumString, sqlType ); 132 } 133 } 134 135 private void guessType(PreparedStatement statement, int index) { 136 ResultSet rs = null; 139 if (! guessed) { 140 try { 141 rs = statement.getConnection().getMetaData().getColumns(catalog, schema, table, column); 142 if ( ! rs.next() ) throw new HibernateException("column not found: " + column); 143 int guessedType = rs.getInt( "DATA_TYPE" ); 144 if ( rs.wasNull() ) throw new HibernateException("column wo type: " + column); 145 if ( rs.next() ) throw new HibernateException("several columns matching: " + column); 146 sqlType = guessedType; 147 guessed = true; 148 } 149 catch (SQLException e) { 150 guessTypeByParameter(statement, index, e); 151 } 152 catch (HibernateException e) { 153 guessTypeByParameter(statement, index, e); 154 } 155 finally { 156 try { 157 if (rs != null) rs.close(); 158 } 159 catch (SQLException e) { 160 161 } 162 } 163 } 164 } 165 166 private void guessTypeByParameter(PreparedStatement statement, int index, Exception e) { 167 log.debug("Unable to guess the column type for enum through conn.getMetadata(): " 168 + e.getMessage() ); 169 try { 170 sqlType = statement.getParameterMetaData().getParameterType( index ); 171 } 172 catch (SQLException ee) { 173 sqlType = Types.INTEGER; 174 log.warn("Unable to guess enum type, default to INTEGER", ee); 175 } 176 guessed = true; 177 } 178 179 private boolean isOrdinal(int paramType) { 180 switch(paramType) { 181 case Types.INTEGER: 182 case Types.NUMERIC: 183 case Types.SMALLINT: 184 case Types.TINYINT: 185 case Types.BIGINT: 186 case Types.DECIMAL: case Types.DOUBLE: case Types.FLOAT: return true; 190 case Types.CHAR: 191 case Types.LONGVARCHAR: 192 case Types.VARCHAR: 193 return false; 194 default: 195 throw new HibernateException("Unable to persist an Enum in a column of SQL Type: " +paramType); 196 } 197 } 198 199 public Object deepCopy(Object value) throws HibernateException { 200 return value; 201 } 202 203 public boolean isMutable() { 204 return false; 205 } 206 207 public Serializable disassemble(Object value) throws HibernateException { 208 return (Serializable ) value; 209 } 210 211 public Object assemble(Serializable cached, Object owner) throws HibernateException { 212 return cached; 213 } 214 215 public Object replace(Object original, Object target, Object owner) throws HibernateException { 216 return original; 217 } 218 219 public void setParameterValues(Properties parameters) { 220 String enumClassName = parameters.getProperty(ENUM); 221 try { 222 enumClass = ReflectHelper.classForName( enumClassName ).asSubclass(Enum .class); 224 } 225 catch (ClassNotFoundException exception) { 226 throw new HibernateException("Enum class not found", exception); 227 } 228 schema = parameters.getProperty(SCHEMA); 230 if ( "".equals( schema ) ) schema = null; 231 catalog = parameters.getProperty(CATALOG); 232 if ( "".equals( catalog ) ) catalog = null; 233 table = parameters.getProperty(TABLE); 234 column = parameters.getProperty(COLUMN); 235 } 236 } 237 | Popular Tags |