-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Mapper une liste de type enum
PostPosted: Mon Sep 01, 2008 4:16 am 
Newbie

Joined: Mon Sep 01, 2008 3:42 am
Posts: 3
Boujour,

J'aurais voulu savoir si il était possible avec les annotations de mapper une liste contenant des types énumérés. J'arrive à le faire pour une liste, pour une enum, mais pas les deux combinées.

Exemple :

Code:
enum DAYS { Lundi, Mardi, Mercredi, Jeudi, Vendredi}

public class Person {

   List<DAYS> freeDays;
   
        @ ????
   public List<DAYS> getFreeDays(){
      return this.freeDays;
   }   
}


Je pourrais évidemment faire une class Days plutôt qu'une enum mais j'y perdrais quelques avantages.

Si vous avez une idée ou une piste, merci d'avance.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2008 9:49 am 
Beginner
Beginner

Joined: Mon Jan 10, 2005 7:14 am
Posts: 32
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.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 03, 2008 9:23 am 
Newbie

Joined: Mon Sep 01, 2008 3:42 am
Posts: 3
Tout d'abord merci pour ta réponse,

effectivement ça a l'air compliqué, je ne m'attendais pas à ça, et je pensais que c'était un cas bien plus courant. Dans tout les cas je vais étudier ta proposition, encore merci de ton aide.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 03, 2008 10:20 am 
Beginner
Beginner

Joined: Mon Jan 10, 2005 7:14 am
Posts: 32
En fait je me rends compte que ma solution ne correspond pas vraiment à ton problème, ça m'apprendra à lire trop vite lol

Ce que je t'ai montré, c'est comment persister les énumérations de manière un peu plus évoluée que ce que permet Hibernate par défaut, c'est-à-dire stocker en base le nom de la valeur d'énumération. Ma solution permet d'associer un identifiant à chaque valeur d'énumération et de stocker cet identifiant en base (et non plus le nom de la valeur d'énumération) et inversement de retrouver une valeur d'énumération à partir de cet identifiant. Et pour ce faire j'ai utilisé les user types de Hibernate.

D'après ce que j'ai compris, quand tu as besoin de persister des objets avec des types non standards (et une liste de valeurs d'énumération ne me paraît pas un type standard), tu dois passer par les user types Hibernate, c'est même une pratique recommandée. C'est donc ce que tu risques d'avoir à faire. Une idée pourrait être de transformer ta liste en chaîne de caractères avec les noms des valeurs d'énumération séparées par une virgule. Il suffirait de quelques adaptations par rapport à mon exemple, en particulier l'implémentation des méthodes nullSafeGet et nullSafeSet. Mais je pense que ça vaut le coup d'essayer ;)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 04, 2008 8:45 am 
Newbie

Joined: Mon Sep 01, 2008 3:42 am
Posts: 3
En continuant mes recherches, je suis tombé sur cette article : http://juliusdev.blogspot.com/2008/04/h ... enums.html

Pour ceux qui auraient le même type de problème l'annotation @CollectionOfElements semble résoudre le problème.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.