2011-01-20 13 views
7

Abbiamo utilizzato GenericEnumUserType per le nostre enumerazioni estendibili e le nostre classi non vengono caricate in JBoss 6, su un contenitore Hibernate 3.6+.java.lang.verifyError sul tipo di utente specifico di ibernazione

Il seguente errore viene generato

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

il seguente codice

type = (NullableType)TypeFactory.basic(identifierType.getName()); 

risposta

11

Sfortunatamente @Enumerated non funziona se è necessario serializzare in base a qualcosa di diverso dall'ordinum o nome di Enum. Sono riuscito a trovare una soluzione (leggermente modificata da 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

Non c'è TypeFactory.basic (String) in Hibernate 3.6 più. Confronta i javadocs:

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

Penso che sia giunto il momento di passare da una UserType personalizzato allo standard @Enumerated :-)

+4

Sfortunatamente è possibile utilizzare solo @Enumerato se si esegue la serializzazione in base all'ordinum o al nome Enum. Ci sono casi in cui questo non è appropriato. – mtpettyp

+1

Posso confermare cosa sta dicendo mtpettyp. Un caso comune è quando hai sostituito i "numeri magici" con un enum, ma devi comunque conservare i dati originali. – samspot

Problemi correlati