View Javadoc

1   /**
2    * Generated by Mod4j at Mon Oct 20 22:16:44 CEST 2008
3    */
4   package org.company.thesandbox.data;
5   
6   import java.io.Serializable;
7   import java.lang.reflect.Method;
8   import java.sql.PreparedStatement;
9   import java.sql.ResultSet;
10  import java.sql.SQLException;
11  import java.util.Properties;
12  
13  import org.hibernate.HibernateException;
14  import org.hibernate.type.NullableType;
15  import org.hibernate.type.TypeFactory;
16  import org.hibernate.usertype.ParameterizedType;
17  import org.hibernate.usertype.UserType;
18  
19  /**
20   * Implements a generic enum user type identified / represented by a single identifier / column.
21   * <p>
22   * <ul>
23   * <li>The enum type being represented by the certain user type must be set by using the 'enumClass'
24   * property.</li>
25   * <li>The identifier representing a enum value is retrieved by the identifierMethod. The name of
26   * the identifier method can be specified by the 'identifierMethod' property and by default the
27   * name() method is used.</li>
28   * <li>The identifier type is automatically determined by the return-type of theidentifierMethod.d34
29   * </li>
30   * <li>The valueOfMethod is the name of the static factory method returning the enumeration object
31   * being represented by the given indentifier. The valueOfMethod's name can be specified by setting
32   * the 'valueOfMethod' property. The default valueOfMethod's name is 'valueOf'.</li>
33   * </p>
34   * <p>
35   * Example of an enum type represented by an int value: <code>
36   * public enum SimpleNumber {
37   *   Unknown(-1), Zero(0), One(1), Two(2), Three(3);
38   *   int value;
39   *   protected SimpleNumber(int value) {
40   *       this.value = value;
41   *       }
42   * 
43   *   public int toInt() { return value; }
44   *   public SimpleNumber fromInt(int value) {
45   *         switch(value) {
46   *          case 0: return Zero;
47   *         case 1: return One;
48   *         case 2: return Two;
49   *         case 3: return Three;
50   *         default:
51   *                 return Unknown;
52   *     }
53   *   }
54   * }
55   * </code>
56   * <p>
57   * The Mapping would look like this: <code>
58   *    <typedef name="SimpleNumber" class="GenericEnumUserType">
59   *        <param name="enumClass">SimpleNumber</param>
60   *        <param name="identifierMethod">toInt</param>
61   *        <param name="valueOfMethod">fromInt</param>
62   *    </typedef>
63   *    <class ...>
64   *      ...
65   *     <property name="number" column="number" type="SimpleNumber"/>
66   *    </class>
67   * </code>
68   * 
69   * @author Martin Kersten
70   * @since 05.05.2005
71   */
72  
73  public class GenericEnumUserType implements UserType, ParameterizedType {
74      private static final String DEFAULT_IDENTIFIER_METHOD_NAME = "id";
75  
76      private static final String DEFAULT_VALUE_OF_METHOD_NAME = "value";
77  
78      private Class<? extends Enum> enumClass;
79  
80      private Class<?> identifierType;
81  
82      private Method identifierMethod;
83  
84      private Method valueOfMethod;
85  
86      private NullableType type;
87  
88      private int[] sqlTypes;
89  
90      public void setParameterValues(Properties parameters) {
91          String enumClassName = parameters.getProperty("enumClass");
92          try {
93              enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
94          } catch (ClassNotFoundException cfne) {
95              throw new HibernateException("Enum class not found", cfne);
96          }
97  
98          String identifierMethodName = parameters.getProperty("identifierMethod",
99                  DEFAULT_IDENTIFIER_METHOD_NAME);
100 
101         try {
102             identifierMethod = enumClass.getMethod(identifierMethodName, new Class[0]);
103             identifierType = identifierMethod.getReturnType();
104         } catch (Exception e) {
105             throw new HibernateException("Failed to obtain identifier method", e);
106         }
107 
108         type = (NullableType) TypeFactory.basic(identifierType.getName());
109 
110         if (type == null)
111             throw new HibernateException("Unsupported identifier type " + identifierType.getName());
112 
113         sqlTypes = new int[] { type.sqlType() };
114 
115         String valueOfMethodName = parameters.getProperty("valueOfMethod",
116                 DEFAULT_VALUE_OF_METHOD_NAME);
117 
118         try {
119             valueOfMethod = enumClass.getMethod(valueOfMethodName, new Class[] { identifierType });
120         } catch (Exception e) {
121             throw new HibernateException("Failed to obtain valueOf method", e);
122         }
123     }
124 
125     public Class returnedClass() {
126         return enumClass;
127     }
128 
129     public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
130             throws HibernateException, SQLException {
131         Object identifier = type.get(rs, names[0]);
132         if (rs.wasNull()) {
133             return null;
134         }
135 
136         try {
137             return valueOfMethod.invoke(enumClass, new Object[] { identifier });
138         } catch (Exception e) {
139             throw new HibernateException("Exception while invoking valueOf method '"
140                     + valueOfMethod.getName() + "' of " + "enumeration class '" + enumClass + "'",
141                     e);
142         }
143     }
144 
145     public void nullSafeSet(PreparedStatement st, Object value, int index)
146             throws HibernateException, SQLException {
147         try {
148             if (value == null) {
149                 st.setNull(index, type.sqlType());
150             } else {
151                 Object identifier = identifierMethod.invoke(value, new Object[0]);
152                 type.set(st, identifier, index);
153             }
154         } catch (Exception e) {
155             throw new HibernateException("Exception while invoking identifierMethod '"
156                     + identifierMethod.getName() + "' of " + "enumeration class '" + enumClass
157                     + "'", e);
158         }
159     }
160 
161     public int[] sqlTypes() {
162         return sqlTypes;
163     }
164 
165     public Object assemble(Serializable cached, Object owner) throws HibernateException {
166         return cached;
167     }
168 
169     public Object deepCopy(Object value) throws HibernateException {
170         return value;
171     }
172 
173     public Serializable disassemble(Object value) throws HibernateException {
174         return (Serializable) value;
175     }
176 
177     public boolean equals(Object x, Object y) throws HibernateException {
178         return x == y;
179     }
180 
181     public int hashCode(final Object x) throws HibernateException {
182         return x.hashCode();
183     }
184 
185     public boolean isMutable() {
186         return false;
187     }
188 
189     public Object replace(Object original, Object target, Object owner) throws HibernateException {
190         return original;
191     }
192 }