J'ai eu le même problème à gérer avec une contrainte qui était de pouvoir stocker un identifiant numérique pour chaque valeur d'énumération. J'avais trouvé une solution sur le web (je ne sais plus où ...) basée sur l'utilisation des user types Hibernate. Le principe c'est de définir un type Hibernate pour gérer les énumérations, ce type est ensuite chargée de convertir ton énumération depuis / vers la base.
Ci-dessous le code de ce user type Hibernate :
Code:
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<? extends Enum> enumClass;
private Class<?> identifierType;
private Method identifierMethod;
private Method valueOfMethod;
private NullableType type;
private int[] sqlTypes;
public void setParameterValues(Properties parameters) {
String enumClassName = parameters.getProperty("enumClass");
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);
}
}
public Class returnedClass() {
return enumClass;
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
Object identifier = type.get(rs, names[0]);
if (identifier == null) {
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);
}
}
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);
}
}
public int[] sqlTypes() {
return sqlTypes;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
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;
}
}
Ci-dessous le code de mon énumération. Une seule valeur d'énumération pour l'instant, mais j'en ai prévu d'autres pour plus tard lol J'utilise des constructeurs sur mes valeurs d'énumération pour pouvoir stocker en base autre chose que le nom de l'enum literal (un code numérique par exemple).
Code:
public enum ResourceType implements java.io.Serializable
{
/**
*
*/
EMPLOYEE("EMPLOYEE");
private java.lang.String id;
/**
* ResourceType constructor
*/
private ResourceType(java.lang.String id)
{
this.id = id;
}
/**
* Return the ResourceType from a string value
* @return ResourceType enum object
*/
public static ResourceType fromString(java.lang.String value)
{
return valueOf(value);
}
/**
* Return a Collection of all literal values for this enumeration
* @return java.util.Collection literal values
*/
public static java.util.Collection literals()
{
final java.util.Collection<String> literals = new java.util.ArrayList<String>(values().length);
for (int i = 0; i < values().length; i++)
{
literals.add(values()[i].name());
}
return literals;
}
public java.lang.String toId() {
return id;
}
public static ResourceType fromId(java.lang.String value) {
if ("EMPLOYEE".equals(value)) return EMPLOYEE;
return null;
}
}
Enfin au niveau de ton champ enum, tu fais comme ça :
Code:
@javax.persistence.Column(name = "TYPE", nullable = false, insertable = true, updatable = true, columnDefinition = "VARCHAR(20)")
@org.hibernate.annotations.Type (
type="t4.core.commons.GenericEnumUserType",
parameters= {
@org.hibernate.annotations.Parameter(
name="enumClass",
value="t4.core.commons.resource.internal.ResourceType"),
@org.hibernate.annotations.Parameter(
name="identifierMethod",
value="toId"),
@org.hibernate.annotations.Parameter(
name="valueOfMethod",
value="fromId")
}
)
@org.hibernate.validator.NotNull
public ResourceType getType()
{
return type;
}
Tu définis donc 3 paramètres pour le type enum Hibernate :
- enumClass : nom de la classe d'énumération
- identifierMethod : nom de la méthode qui retourne la valeur que tu veux stocker en base (utilisée pour la conversion Java -> base)
- valueOfMethod : nom de la méthode qui retourne l'enum literal correspondant à la valeur stockée en base (utiliser pour la conversion base -> Java)
Voilà ... Un peu compliqué mais j'espère que ça t'aidera.