2013-03-07 48 views
2

我想要在數據庫上有一個枚舉類型並將其轉換爲java,我寫了一個EnumUserType類來執行轉換,但它不能識別PGobject類。使用Hibernate從Postgres到Java的枚舉

public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor si, Object owner) 
     throws HibernateException, SQLException { 
    Object object = rs.getObject(names[0]); 
    if (rs.wasNull()) { 
     return null; 
    } 

    if (object instanceof PGobject) { 
     //code doesn't reach this line 
    } 

    log.info(object.getClass()); // prints class org.postgresql.util.PGobject 
    return null; 
} 

我檢查了,我有完全相同的postgresql驅動程序版本。 我看到這篇文章:Java enum with Eclipselink。這是一個我也會嘗試的解決方案,但我的主要問題是:顯然它是同一個班級,爲什麼它不被認可?我可以擁有兩個具有相同名稱和包的不同類嗎?如果我仍然需要在Postgres中使用枚舉,我該如何解決它以正確映射到我的Java枚舉?

編輯:

我試圖做一個:

PGobject pg = (PGobject) object; 

,它拋出一個類轉換異常:

org.postgresql.util.PGobject cannot be cast to org.postgresql.util.PGobject 

感謝

+2

爲什麼不用'rs.getString()'來代替?它應該以字符串AFAIK的形式返回枚舉值。 – 2013-03-07 22:51:19

+0

剛剛嘗試過,它引發一個異常:org.postgresql.util.PGobject不能轉換爲java.lang.String – Migore 2013-03-08 12:37:50

+0

忽視我以前的評論,還有其他的東西丟失。剛試過,它的工作,謝謝!這解決了我的問題,但我仍然對這個問題感到好奇。 – Migore 2013-03-08 12:56:49

回答

0

我用一個泛型類使用作爲映射枚舉的類型。然後,可以使用它映射所有的枚舉。

類是這樣的:

public class GenericEnumUserType implements UserType, ParameterizedType { 

private static final String DEFAULT_IDENTIFIER_METHOD_NAME = "name"; 
private static final String DEFAULT_VALUE_OF_METHOD_NAME = "valueOf"; 

private Class enumClass; 
private Class identifierType; 
private Method identifierMethod; 
private Method valueOfMethod; 
private NullableType type; 
private int[] sqlTypes; 

@Override 
public void setParameterValues(Properties parameters) { 
    String enumClassName = parameters.getProperty("enumClassName"); 
    try { 
     enumClass = Class.forName(enumClassName).asSubclass(Enum.class); 
    } catch (ClassNotFoundException cfne) { 
     throw new HibernateException("Enum class not found", cfne); 
    } 

    String identifierMethodName = parameters.getProperty("identifierMethod", DEFAULT_IDENTIFIER_METHOD_NAME); 

    try { 
     identifierMethod = enumClass.getMethod(identifierMethodName, new Class[0]); 
     identifierType = identifierMethod.getReturnType(); 
    } catch (Exception e) { 
     throw new HibernateException("Failed to obtain identifier method", e); 
    } 

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

    if (type == null) { 
     throw new HibernateException("Unsupported identifier type " + identifierType.getName()); 
    } 

    sqlTypes = new int[] { type.sqlType() }; 

    String valueOfMethodName = parameters.getProperty("valueOfMethod", DEFAULT_VALUE_OF_METHOD_NAME); 

    try { 
     valueOfMethod = enumClass.getMethod(valueOfMethodName, new Class[] { identifierType }); 
    } catch (Exception e) { 
     throw new HibernateException("Failed to obtain valueOf method", e); 
    } 
} 

@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]); 
    if (rs.wasNull()) { 
     return null; 
    } 

    try { 
     return valueOfMethod.invoke(enumClass, new Object[] { identifier }); 
    } catch (Exception e) { 
     throw new HibernateException("Exception while invoking " + "valueOf method " + valueOfMethod.getName() 
       + " of enumeration class " + enumClass, e); 
    } 
} 

@Override 
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 
    try { 
     if (value == null) { 
      st.setNull(index, type.sqlType()); 
     } else { 
      Object identifier = identifierMethod.invoke(value, new Object[0]); 
      type.set(st, identifier, index); 
     } 
    } catch (Exception e) { 
     throw new HibernateException("Exception while invoking identifierMethod " + identifierMethod.getName() 
       + " of enumeration class " + enumClass, e); 
    } 
} 

@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(); 
} 

@Override 
public boolean isMutable() { 
    return false; 
} 

@Override 
public Object replace(Object original, Object target, Object owner) throws HibernateException { 
    return original; 
}} 

Enum類應該是這樣的:

public enum AccountStatus { 
ACTIVE(1), BLOCKED(2), DELETED(3); 

private AccountStatus(int id) { 
    this.id = id; 
} 

private int id; 

public int getId() { 
    return id; 
} 

public void setId(int id) { 
    this.id = id; 
} 

public static AccountStatus valueOf(int id) { 
    switch (id) { 
    case 1: 
     return ACTIVE; 
    case 2: 
     return BLOCKED; 
    case 3: 
     return DELETED; 
    default: 
     throw new IllegalArgumentException(); 
    } 
}} 

靜態方法 「的valueOf」 有必要從存儲在數據庫中的Java對象ID轉換。

然後,Hibernate映射是這樣的:

<hibernate-mapping> 
<typedef class="path.to.GenericEnumUserType" name="accountStatusType"> 
    <param name="enumClassName">com.systemonenoc.hermes.ratingengine.persistence.constants.AccountStatus</param> 
    <param name="identifierMethod">getId</param> 
</typedef> 
<class name="package.to.class.with.enum.Account" table="account" schema="public"> 
    <property name="accountStatus" type="accountStatusType" column="account_status" not-null="true" /> 
[...] 
</hibernate-mapping> 

所以,你必須聲明爲一個類型的類GenericEnumUserType用typedef和方法獲取枚舉的ID(在這種情況下,的getId( ))。在你的數據庫中,將把id作爲值存儲在一個整數列中,而在java中你將擁有枚舉對象。