KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > type > EnumType


1 //$Id: EnumType.java,v 1.7 2005/08/03 23:30:18 epbernard Exp $
2
package org.hibernate.type;
3
4 import java.io.Serializable JavaDoc;
5 import java.lang.reflect.Method JavaDoc;
6 import java.sql.PreparedStatement JavaDoc;
7 import java.sql.ResultSet JavaDoc;
8 import java.sql.SQLException JavaDoc;
9 import java.sql.Types JavaDoc;
10 import java.util.HashMap JavaDoc;
11 import java.util.Map JavaDoc;
12 import java.util.Properties JavaDoc;
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 /**
23  * Enum type mapper
24  * Try and find the appropriate SQL type depending on column metadata
25  * @author Emmanuel Bernard
26  */

27 public class EnumType implements UserType, ParameterizedType {
28     //TODO cache metadata
29
private static Log log = LogFactory.getLog(EnumType.class);
30     private static final boolean IS_TRACE_ENABLED;
31     static {
32         //cache this, because it was a significant performance cost
33
IS_TRACE_ENABLED = LogFactory.getLog( StringHelper.qualifier( Type.class.getName() ) ).isTraceEnabled();
34     }
35
36     public static final String JavaDoc ENUM = "enumClass";
37     public static final String JavaDoc SCHEMA = "schema";
38     public static final String JavaDoc CATALOG = "catalog";
39     public static final String JavaDoc TABLE = "table";
40     public static final String JavaDoc COLUMN = "column";
41
42     private static Map JavaDoc<Class JavaDoc,Object JavaDoc[]> enumValues = new HashMap JavaDoc<Class JavaDoc, Object JavaDoc[]>();
43
44     private Class JavaDoc<? extends Enum JavaDoc> enumClass;
45     private String JavaDoc column;
46     private String JavaDoc table;
47     private String JavaDoc catalog;
48     private String JavaDoc schema;
49     private boolean guessed = false;
50     private int sqlType = Types.INTEGER; //before any guessing
51

52     public int[] sqlTypes() {
53         return new int[] { sqlType };
54     }
55
56     public Class JavaDoc returnedClass() {
57         return enumClass;
58     }
59
60     public boolean equals(Object JavaDoc x, Object JavaDoc y) throws HibernateException {
61         return x == y;
62     }
63
64     public int hashCode(Object JavaDoc x) throws HibernateException {
65         return x.hashCode();
66     }
67
68     public Object JavaDoc nullSafeGet(ResultSet JavaDoc rs, String JavaDoc[] names, Object JavaDoc owner) throws HibernateException, SQLException JavaDoc {
69         Object JavaDoc 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 JavaDoc) {
77             Object JavaDoc[] values = enumValues.get(enumClass);
78             if (values == null) {
79                 try {
80                     Method JavaDoc method = null;
81                     method = enumClass.getDeclaredMethod( "values", new Class JavaDoc[0] );
82                     values = (Object JavaDoc[]) method.invoke(null, new Object JavaDoc[0] );
83                     enumValues.put( enumClass, values );
84                 }
85                 catch (Exception JavaDoc e) {
86                     throw new HibernateException("Error while accessing enum.values(): " + enumClass, e);
87                 }
88             }
89             int ordinal = ( (Number JavaDoc) object ).intValue();
90             if (ordinal < 0 || ordinal >= values.length) {
91                 throw new IllegalArgumentException JavaDoc("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 JavaDoc name = (String JavaDoc) 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 JavaDoc iae) {
107                 throw new IllegalArgumentException JavaDoc("Unknown name value for enum " + enumClass + ": " + name, iae);
108             }
109         }
110     }
111
112     public void nullSafeSet(PreparedStatement JavaDoc st, Object JavaDoc value, int index) throws HibernateException, SQLException JavaDoc {
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 JavaDoc) value ).ordinal();
121             if ( IS_TRACE_ENABLED ) {
122                 log.debug("Binding '" + ordinal + "' to parameter: " + index);
123             }
124             st.setObject( index, new Integer JavaDoc(ordinal), sqlType );
125         }
126         else {
127             String JavaDoc enumString = ( (Enum JavaDoc) 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 JavaDoc statement, int index) {
136         //TODO avoid nested TCF
137
//TODO use SQLExceptino wrapper?
138
ResultSet JavaDoc 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 JavaDoc 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 JavaDoc e) {
160
161                 }
162             }
163         }
164     }
165
166     private void guessTypeByParameter(PreparedStatement JavaDoc statement, int index, Exception JavaDoc 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 JavaDoc 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: //for Oracle Driver
187
case Types.DOUBLE: //for Oracle Driver
188
case Types.FLOAT: //for Oracle Driver
189
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 JavaDoc deepCopy(Object JavaDoc value) throws HibernateException {
200         return value;
201     }
202
203     public boolean isMutable() {
204         return false;
205     }
206
207     public Serializable JavaDoc disassemble(Object JavaDoc value) throws HibernateException {
208         return (Serializable JavaDoc) value;
209     }
210
211     public Object JavaDoc assemble(Serializable JavaDoc cached, Object JavaDoc owner) throws HibernateException {
212         return cached;
213     }
214
215     public Object JavaDoc replace(Object JavaDoc original, Object JavaDoc target, Object JavaDoc owner) throws HibernateException {
216         return original;
217     }
218
219     public void setParameterValues(Properties JavaDoc parameters) {
220         String JavaDoc enumClassName = parameters.getProperty(ENUM);
221         try {
222             //TODO use ReflectHelper.classForName(String, Class) in >= core 3.1beta2
223
enumClass = ReflectHelper.classForName( enumClassName ).asSubclass(Enum JavaDoc.class);
224         }
225         catch (ClassNotFoundException JavaDoc exception) {
226             throw new HibernateException("Enum class not found", exception);
227         }
228         //nullify unnullified properties yuck!
229
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