2011-01-20 3 views

答えて

11

残念ながら@ Enumeratedは、Enumの序数または名前以外のものに基づいてシリアル化する必要がある場合は機能しません。私は解決策を見つけることに成功しました(hereからわずかに変更されました)。

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.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<? extends Enum> enumClass; 
    private Class<?> identifierType; 
    private Method identifierMethod; 
    private Method valueOfMethod; 
    private static final String defaultIdentifierMethodName = "name"; 
    private static final String defaultValueOfMethodName = "valueOf"; 
    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; 
    } 

    @Override 
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) 
     throws HibernateException, SQLException 
    { 
     Object identifier = type.get(rs, names[0]); 
     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; 
    } 
} 
2

次のコードに

#abc state=Create: java.lang.NoSuchMethodError: org.hibernate.type.Type 
Factory.basic(Ljava/lang/String;)Lorg/hibernate/type/Type; 

を投げられる

にHibernate 3.6にはTypeFactory.basic(文字列)はもうありません。 Javadocを比較:

http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/type/TypeFactory.html http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/type/TypeFactory.html私はそれが今から移動する時間だと思う

カスタムUserTypeを標準@Enumerated :-)

+4

残念ながら、@ EnumeratedはEnum序数または名前に基づいてシリアル化する場合にのみ使用できます。これが適切でない場合があります。 – mtpettyp

+1

mtpettypが何を言っているかを確認できます。よくあるケースは、「マジックナンバー」を列挙型に置き換えたときですが、元のデータを保持する必要があります。 – samspot