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 :

Récupérer une Class générique


Sujet :

Langage Java

  1. #1
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut Récupérer une Class générique
    Bonjour!

    J'ai une interface de ce goût là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public interface ServiceProvider<T> {
     
        T getService();
     
        Class<T> getServiceType();
    }
    où T représente l'interface exposée par le service.

    Dans le cas où T est aussi un type généric, ça coince.
    Par exemple, prenons T = List<Runnable>, mon implémentation ressemblerait à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Provider implements ServiceProvider<List<Runnable>> {
        ...
     
        public List<Runnable> getService()
        {
            return monService;
        }
     
        public Class<List<Runnable>> getServiceType()
        {
            return ???;
        }
    }
    Je n'arrive pas à trouver une syntaxe qui satisfasse le compilo.
    Est-ce possible?
    Dois-je modifier mon interface 'ServiceProvider'?

    Merci.

  2. #2
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    bonjour,

    le code est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	public Class<List<Runnable>> getServiceType() {
    		return (Class<List<Runnable>>) monService.getClass();
    	}
    tu aura un warning, mais ca passe
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Merci pour la réponse, malheureusement, cela convient pas car je vais renvoyer la classe de l'implémentation (ArrayList ou LinkedList par exemple) alors que je souhaite renvoyer l'interface du service (List<Runnable>)

  4. #4
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    pour quel raison as tu besoin du type ?
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Lorsqu'une entité à besoin d'un certain type de service, elle va voir qui le propose via les providers.

    Si j'affiche la classe de l'implémentation, elle pourrait éventuellement trouver des interfaces implémentées pour d'autres raisons.
    De plus, d'un point de vue conceptuel, le service doit présenter l'interface et non l'implémentation.

  6. #6
    Membre émérite
    Avatar de divxdede
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    525
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2004
    Messages : 525
    Par défaut
    Citation Envoyé par Deaf Voir le message
    Lorsqu'une entité à besoin d'un certain type de service, elle va voir qui le propose via les providers.

    Si j'affiche la classe de l'implémentation, elle pourrait éventuellement trouver des interfaces implémentées pour d'autres raisons.
    De plus, d'un point de vue conceptuel, le service doit présenter l'interface et non l'implémentation.
    Justement je m'attends plus à un fonctionnement approchant ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
         public interface ServiceProvider {
     
               public <T> T getService( Class<T> classe );
         }
    C'est l'appelant qui passe au provider le type de service qu'il recherche.
    Je peu a ce stade écrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     List<Toto> a =  monProvider.getService( List<Toto>.class );
    Et avoir une implémentation de mon service utlisant une ArrayList.
    De plus, je n'aime pas trop utiliser des collections "brut" pour representer une notion de service. C'est trop abstrait, la liste ne te donne pas d'indication sur ce que represente ton ensemble. Par exemple List<Client> ne te dit pas qu'il s'agit d'un service te donnant la liste des clients mauvais payeur !! l'interface de ton service est floue.

  7. #7
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    tes types de service seront fixe ? si oui, tu peux peut être définir un enum avec tous les types et utiliser ensuite cet enum.
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    @divxdede

    En ce qui concerne l'utilisation de l'interface List, ce n'était qu'un exemple d'interface générique. En réalité, j'utilise des interfaces de mon cru.

    Malheureusement, ce bout de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Toto> a =  monProvider.getService( List<Toto>.class );
    ne passe pas le compilateur. Ce changement est sujet au même problème 'technique' que le code originel.

    Vu ce que tu as proposé, je préfère préciser un point: Mon provider ne propose qu'un seul service, donc mettre le type en paramètre ne me semble pas judicieux. Cela pourrait laisser penser que le provider va choisir un service en fonction du type.
    Mais bon, là, c'est du pinaillage et on s'éloigne du sujet


    @Alkhan
    Non, les types ne sont pas fixes. Je suis dans une architecture modulaire, donc ce n'est pas possible d'utiliser d'enum pour représenter les services...


    Merci à vous de vous pencher sur mon problème.

  9. #9
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    bien alors est il possible que tu retourne un le type sous forme de chaîne sauf si cela pause un problème à un autre niveau de ton programme.

    Cela peux paraitre étrange mais au moins tu auras le bon type. je pense alors à 2 solutions :

    soit tu gardes ton interface et dans la classe qui l'implemente tu écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    java.util.List<java.lang.Runnable>
    String getServiceType() {
    	return "java.util.List<java.lang.Runnable>";
    }
    soit ton interface devient une classe abstraite qui definit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    String getServiceType() {
    	Type tI = this.getClass().getGenericSuperclass();
    	ParameterizedType p = (ParameterizedType) tI;
    	return p.getActualTypeArguments()[0].toString();
    }
    évidement, il faudra tester si c'est un generic, la c'est pour l'exemple.
    Cela peut il convenir ?
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Je pense que le passage en chaîne me semble une des seules solutions acceptables.

    Ceci dit, si quelqu'un trouve un autre moyen je reste preneur, au moins pour ma culture J

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    pour information, "List<Toto>.class" et "List<Object>.class" sont des valeurs strictement identiques pour la jvm, puisque le generic ne sert qu'au compilateur.

  12. #12
    Membre émérite
    Avatar de divxdede
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    525
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2004
    Messages : 525
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    pour information, "List<Toto>.class" et "List<Object>.class" sont des valeurs strictement identiques pour la jvm, puisque le generic ne sert qu'au compilateur.
    Effectivement, il s'agit uniquement d'un sucre syntaxique utilisé par la compilation.


    Ceci dit "List<String>.class" n'est effectivement pas autorisé par le compilateur et je suis assez surpris...

  13. #13
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    c'est normal, puisque ça ne veux rien dure. C'est List.class qu'il faut utiliser!

  14. #14
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Sauf que le compilo n'accepte pas List.class dans mon exemple

    Même si je suis conscient que cela ne change rien à l'exécution, j'aurai aimé faire un truc propre (et qui compile...)

  15. #15
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    finalement, tu a choisi quel solution ?
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  16. #16
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    J'ai bien peur qu'on touche à une limitation des génériques Java (il y en a un paquet, après tout,) et qu'il te faille faire moins propre, genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static <T> T getService(Class<?> classe) {
      if(classe == List.class) {
        return (T)(new ArrayList());
      } else if(classe == Map.class) {
        return (T)(new HashMap());
      } else {
        throw new IllegalArgumentException();
      }
    }
    En sachant qu'il n'y a pas de vérification statique que T est bien de la classe fournie, et que si on t'appelle en attendant un Date et qu'on te file Integer.class en paramètre, ça va faire un ClassCastException, parce que les deux ne correspondent pas mais ça compile quand même.

    La seule manière propre que je vois, c'est de se taper des méthodes getListService(), getMapService(), ... Et ainsi de suite pour chaque type générique qui puisse être un service.
    Et d'adapter le reste du code autour de cette limitation.
    Pour le dire autrement, de s'interdire d'avoir "n'importe quel" service qui soit de type paramétré. Adapter pour faire autrement, donc.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  17. #17
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Vu que cela semble être une limitation des Generics, je vais être obligé de retirer la généricité de la méthode getServiceType(), c'est dommage, mais si j'ai pas le choix.

    J'arrive deux options:
    - Le passage en String du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public interface ServiceProvider<T> {
     
        T getService();
     
        String getServiceType();
    }
    - Conserver une class, mais sans contrainte:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public interface ServiceProvider<T> {
     
        T getService();
     
        Class<?> getServiceType();
    }
    Dans les deux cas, j'ai bien peur que ma généricité ne me soit plus d'une grande utilité. Du coup, je vais peut-être opter pour une solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public interface ServiceProvider {
     
        Object getService();
     
        String/Class<?> getServiceType();
    }

  18. #18
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Citation Envoyé par thelvin Voir le message
    J'ai bien peur qu'on touche à une limitation des génériques Java (il y en a un paquet, après tout,) et qu'il te faille faire moins propre, genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static <T> T getService(Class<?> classe) {
      if(classe == List.class) {
        return (T)(new ArrayList());
      } else if(classe == Map.class) {
        return (T)(new HashMap());
      } else {
        throw new IllegalArgumentException();
      }
    }
    pour ça tu peux très bien faire ceci:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static <T> T getService(Class<? extends T> classe) {
      if(classe == List.class) {
        return (T)(new ArrayList());
      } else if(classe == Map.class) {
        return (T)(new HashMap());
      } else {
        throw new IllegalArgumentException();
      }
    }
    ca forcera au moins l'appelant, mais ça va pas te servir à grand chose, car comme on est dans une service, tu va probablement appeler 'à l'aveugle' dans ta factory, donc les generics ne serviront à rien

  19. #19
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    ça va pas te servir à grand chose, car comme on est dans une service, tu va probablement appeler 'à l'aveugle' dans ta factory, donc les generics ne serviront à rien
    Exactement! Le seul but des generics était, dans mon cas, d'ajouter des contrôles à la compilation pour éviter de faire n'importe quoi en assurant que le type déclaré correspondait bien au service renvoyé.

  20. #20
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Citation Envoyé par Deaf Voir le message
    Exactement! Le seul but des generics était, dans mon cas, d'ajouter des contrôles à la compilation pour éviter de faire n'importe quoi en assurant que le type déclaré correspondait bien au service renvoyé.
    ces controle ne pourront pas exister, puisque quand tu appelera une classe de service, tu n'aura aucune idée des type renvoyé réellement, du moins au moment de la compilation. Maintenant, si ton but était de forcer le Type dans le service même (éviter des bourde dans le service), pourquoi le pas plutot opter pour cette option:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public interface Service<T> {
     
      public T createObject();
      public Class<T> getType();
    }  
     
     
    public class MachinService extends Service<Machin> {
     // il est maintenant impossible pour le codeur de ce service de revoyer autre chose que Machin ou de retourner autre chose que Class<Machin> depuis getType
    }
    Ou alors j'ai rien compris au but recherché

Discussions similaires

  1. Réponses: 9
    Dernier message: 15/02/2013, 23h27
  2. ClassCastException dans une classe générique
    Par lion13 dans le forum Langage
    Réponses: 2
    Dernier message: 07/05/2008, 19h35
  3. [Reflexion] Comment récupérer une class via son chemin python
    Par anthyme dans le forum Général Python
    Réponses: 2
    Dernier message: 27/12/2007, 13h16
  4. Problème avec une classe générique
    Par Core8 dans le forum C++
    Réponses: 3
    Dernier message: 19/03/2007, 03h18
  5. Utilisation d'une classe générique
    Par bandit_debutant dans le forum Langage
    Réponses: 4
    Dernier message: 06/12/2006, 16h54

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