IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Retrouver le type de class depuis uun type paramétré


Sujet :

Langage Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 109
    Points : 57
    Points
    57
    Par défaut Retrouver le type de class depuis uun type paramétré
    Bonjour,

    j'aimerai paramétriser la méthode suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        public List<User> retrieveAll() {
            return getHibernateTemplate().loadAll(User.class);
        }
    D'une manière générale, le remplacement de "User" par "T" s'est très bien passé dans ma classe, à l'exception de cette méthode, où "T.class" me cause une erreur de compilation :

    Illegal class literal for the type parameter T
    Une idée de ce que je peux utiliser à la place?

    Merci d'avance!

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,



    Le paramétrage existe déjà sur la classe où y-a-t-il seulement la méthode à paramétrer ?

    Dans tous les cas tu ne pourras pas te passer de User.class (il sera juste déplacé).

    a++

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Je l'ai mis en paramètre de ma classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /**
    * @param <T>
    */
    public class BaseDAOImpl<T> extends HibernateDaoSupport implements BaseDAO<T>{
    Je compte par la suite créer des classes qui étendent celle-ci et à ce moment là seulement spécifier le type d'objet a utiliser (extends BaseDAOImpl<User> par exemple) ...

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Comme je le disais tu devras quand même spécifié le type quelque part, sinon il sera perdu...

    Tu pourrais utiliser le type lors de la création de ton DAO, par exemple en la déclarant de la sorte afin de stocker le type de <T> :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class BaseDAOImpl<T> extends HibernateDaoSupport implements BaseDAO<T> {
     
    	/** Le type réel du <T> associé à cette instance. */
    	private final Class<T> tClass;
     
    	public BaseDAOImpl(Class<T> tClass) {
    		this.tClass = tClass;
    		if (this.tClass == null) {
    			throw new NullPointerException();
    		}
    	}
    }
    Ensuite il suffira de définir ta méthode de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	@SuppressWarnings("unchecked")
    	public List<T> retrieveAll() {
    		return getHibernateTemplate().loadAll(this.tClass);
    	}
    Mais attention il faut être sûr et certain que la méthode loadAll() te renvoi toujours des objets du type que tu lui passes dans la liste... sinon tu risque d'avoir de drôle de surprise à l'exécution !

    a++

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Merci beaucoup pour ta réponse.

    Je dois avouer que je suis un peu déçu, je m'imaginais que comme T représentait une classe, on pouvait y faire référence plus simplement. En effet, par la suite, en déclarant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class UserDAOImpl extends BaseDAOImpl<User>
    je défini déjà que le type de ma classe est User. Ca aurait été plus élégant si je ne devais re-définir son type à nouveau dans le constructeur.


    En fait pour la petite histoire, j'ai construit une interface qui définit les méthodes CRUD pour ma DAO, et je voulais leur donner une implémentation générique. Ensuite, je pouvais étendre ces DAOs avec des méthodes spécifiques en fonction de mes entités.

    En gros, ça donnait ceci :

    1) L'interface générique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
     * @param <T>
     */
    public interface BaseDAO<T> {
     
        public void create(T entity);
        public T retrieve(Serializable id);
        public List<T> retrieveAll();
        public void update(T entity);
        public void delete(T entity);
     
    }
    2) L'implémentation générique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    /**
     * @param <T>
     */
    public class BaseDAOImpl<T> extends HibernateDaoSupport implements BaseDAO<T>{
     
        public void create(T entity) {
            getHibernateTemplate().save(entity);
        }
     
        public void delete(T entity) {
            getHibernateTemplate().delete(entity);
        }
     
        public T retrieve(Serializable id) {
            if (id==null) return null;
            return (T) getHibernateTemplate().load(T.class,id);
        }
     
        @SuppressWarnings("unchecked")
        public List<T> retrieveAll() {
            return getHibernateTemplate().loadAll(T.class);
        }
     
        public void update(T entity) {
            getHibernateTemplate().merge(entity);
        }
     
    }
    3) Mon DAO spécialisé

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class UserDAOImpl extends BaseDAOImpl<User> implements UserDAO{
     
    //code personnalisé
     
    }
    Voilà voilà, bin en tout cas encore merci pour ta solution et la rapidité de ta réponse!

  6. #6
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Ce n'est pas bien méchant de redéfinir le type dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class UserDAOImpl extends BaseDAOImpl<User> {
        public UserDAOImpl() {
            super(User.class);
        }
    }


    Maintenant il y a un moyen de s'en passer seulement lorsque tu hérites directement en précisant le type concret (comme dans ce cas), mais alors cela revient à faire un Constructeur assez complexe qui recherchera le type passé lors du extends :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    	protected BaseDAOImpl() {
    		// 1. On récupère le type de la classe courante :
    		Class<?> clazz = this.getClass();
    		// 2. S'il s'agit de BaseDAOImpl cela signifie que l'on a appelé
    		//    le constructeur directement => C'est interdit on ne peut pas
    		//    déterminer le type du paramétrage Generics
    		//    (cette vérificaton permet d'éviter un NullPointer à l'étape 3)
    		if (clazz==BaseDAOImpl.class) {
    			throw new IllegalStateException(
    					"Le constructeur BaseDAOImpl() ne peut pas être appelé directement. " +
    					"Utiliser le constructeur BaseDAOImpl(Class<T>) à la place !");
    		}
     
    		// 3. On recherche la première classe fille (en cas d'héritage successif) :
    		while (clazz.getSuperclass()!=BaseDAOImpl.class) {
    			clazz = clazz.getSuperclass();
    		}
     
    		// 4. Et on récupère la classe parente avec les infos génériques :
    		Type type = clazz.getGenericSuperclass();
     
    		Class<?> parameterizedClass = null;
    		// 5. Si on a utilisé les Generics lors de l'héritage,
    		//    alors on doit obtenir un ParametizedType
    		if (type instanceof ParameterizedType) {
    			// On récupère le type paramétrique défini dans le source
    			ParameterizedType pType = (ParameterizedType) type;
    			Type argType = pType.getActualTypeArguments()[0];
    			// 6. Selon le type défini à l'héritage, on peut avoir 3 cas :
    			if (argType instanceof Class) {
    				// On a un objet 'Class' lorsqu'on précise un type précis lors de l'héritage :
    				// => class UserDAOImpl extends BaseDAOImpl<User> 
    				// Ce type correspond à celui défini dans l'héritage (User ici)
    				// => On a gagné on a retrouvé notre type :
    				parameterizedClass = (Class<?>) argType;
    			}
    			// On peut aussi avoir un 'ParametizedType' si on passe un type Generic :
    			// => class UsersDAOImpl extends BaseDAOImpl<List<User>>
    			// Mais ce cas est délicat car on doit prendre le raw type 'List'
    			// et on perd une partie de l'info dans la foulé...
    			// => Je préfère ne pas gérer ce cas car cela pourrait provoquer des
    			// erreurs plus ou moins bizarre dans le reste du code :(
     
    			// Enfin on peut avoir un 'TypeVariable' si on conserve les Generics :
    			// => class ExtDAOImpl<T> extends BaseDAOImpl<T>
    			// Dans ce cas il n'y a aucun moyen de retrouver le type
    		}
     
    		// On a un warning unchecked car le compilateur ne peut pas vérifier
    		// le type précis des classes. On utilise @SuppressWarnings pour l'ignorer
    		// (=> On prend la responsabilité de la validité des types)
    		@SuppressWarnings("unchecked")
    		Class<T> detectedType = (Class<T>) parameterizedClass;
    		this.tClass = detectedType;
     
    		if (tClass==null) {
    			throw new IllegalStateException(
    					"Le constructeur BaseDAOImpl() ne peut pas détecté le type paramétré. " +
    					"Utiliser le constructeur BaseDAOImpl(Class<T>) à la place !");
    		}
    	}

    Perso je préfères quand même passer explicitement le type, c'est bien plus simple !

    A toi de voir !

    a++

Discussions similaires

  1. Type de class et arguments pour fonctions et new
    Par Alfred12 dans le forum C++
    Réponses: 15
    Dernier message: 19/01/2007, 01h02
  2. Trier un tableau de plusieurs type de classes.
    Par storm_2000 dans le forum Collection et Stream
    Réponses: 8
    Dernier message: 14/01/2007, 15h50
  3. Réponses: 7
    Dernier message: 08/01/2007, 12h11
  4. [.NET2.0][C#]Passage type de classe dans une fonction
    Par SLE dans le forum Windows Forms
    Réponses: 4
    Dernier message: 06/06/2006, 15h48
  5. [CSS] class selon le type d enfants
    Par luta dans le forum Mise en page CSS
    Réponses: 7
    Dernier message: 10/11/2005, 13h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo