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 :

[Généricité] Utilisation de ClassLoader à la place d'un switch/case


Sujet :

Langage Java

  1. #1
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut [Généricité] Utilisation de ClassLoader à la place d'un switch/case
    je precise je suis en 1.4

    je suppose que la question a déjà été posée mais je ne suis pas fichu de mettre la main sur la réponse.

    Voilà, je fait un petit bout de code dans lequel je souhaite traiter de manière générique trois types d'objets. Ces types d'objets sont similaires et j'appelle exactement les mêmes méthodes avec les mêmes arguments. Les traitements à effectuer sont identiques également.

    J'ai donc commencé naïvement en me disant que j'allais m'en sortir avec un switch case basé sur un paramètre que je passe à ma méthode "générique".
    Mais bon je m'en sors mais c'est ultra moche ...

    je me dis qu'il y a surement un moyen de passer par quelque chose de vraiment générique (enfin qui traite ces 3 éléments de manière transparente)

    Je tente donc avec ClassLoader mais je n'y arrive pas tellement. Si qqun avait une petite piste vers quoi m'orienter pour y arriver.

    Voici en gros le code (il est très moche mais c'est pour que vous compreniez mieux en gros quels sont les points où j'ai besoin de générécité)

    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
    switch(type){
    			case PROJ:
                                   // listeCodes est une sorte d'Iterator
    				listeCodes = ProjectCode.load(session, new 
    String[]{"CodeValue","Description","CodeTypeName","ParentObjectId"}, ids);
    				
    				// on parcours cette liste de codes
    				if(listeCodes != null && listeCodes.getCount()>0){
    					
    					Object[] values = new Object[4]; //les objets à insérer dans listeValeurs
    					while(listeCodes.hasNext()){
    						ProjectCode code = (ProjectCode) listeCodes.next();
    // récupération des données en param 2 des loadXXX
    					}
    				}
    				break;
    			case ACT://traitement idem sauf type d'objet différent
    				listeCodes = ActivityCode.load(session, new String[]{"CodeValue","Description","CodeTypeName","ParentObjectId"}, ids);
    				// on parcours cette liste de codes
    				if(listeCodes != null && listeCodes.getCount()>0){
    					
    					Object[] values = new Object[4]; //les objets à insérer dans listeValeurs
    					while(listeCodes.hasNext()){
    						ActivityCode code = (ActivityCode) listeCodes.next();
    					}
    				}
    				break;
    			case RES:
    en gros il me faut (mais le code est faux il me semble) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Class maClasse = ClassLoader.loadClass(/* APPEL d'une fonction qui me renvoie le nom de la classe en focntion de "type"*/)
     
    listeCodes = maClasse.load(session ....
    while(
         maClasse code (maClasse) listeCodes.next();
    // suite des traitements identiques
    est ce proche de la réalité ? du réalisable ?

  2. #2
    Membre éprouvé
    Inscrit en
    Avril 2004
    Messages
    170
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 170
    Par défaut
    C'est presque ca sauf qu'il faut que tu passes par la methode getMethod() de Class pour appeler la méthode load(session,...)

  3. #3
    Membre émérite Avatar de benratti
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    471
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2004
    Messages : 471
    Par défaut
    Si tes classes ont des methodes similaires, ne serait il pas possible que tu fasses une interface qui reprend les methodes communes et tes objets implementent cette interface. Ensuite, tu n'as qu'a travailler sur des objets de ton interface et c'est gagné !

  4. #4
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    En fait ces objets proviennent d'une API sur laquelle je n'ai pas la main ...

    j'aurais dû le préciser ...

  5. #5
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par in
    En fait ces objets proviennent d'une API sur laquelle je n'ai pas la main ...
    2 questions :
    • A quoi correspond le code identique ?
    • Les classes implémentent/héritent-elles d'une interface/classe commune ?
    a++

  6. #6
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    J'ai mis les morceaux identiques pour chaque type en gras dans le premier message. J'espere que c'est assez clair

    Citation Envoyé par adiGuba
    Les classes implémentent/héritent-elles d'une interface/classe commune
    Oui ces classes héritent toutes d'une meme classe. J'avais penser à caster vers le type parent ce parent ne possède pas le méthodes que je souhaite appeler. Je ne crois pas que je puisse passer par ici ...

    En fait tout le code est identique, seul changent les types d'objets sur lesquels appeler les méthodes et le types vers lesquels caster depuis Object...

  7. #7
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par in
    J'ai mis les morceaux identiques pour chaque type en gras dans le premier message. J'espere que c'est assez clair
    C'est tout ? le reste du code à l'intérieur de la boucle while est différent pour chaque type ??? Donc tout ce que tu souhaites c'est une manière de récupérer l'Iterator ?

    a++

  8. #8
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    non non ...

    bon je vais éditer le premier message pour indiquer ce qui est différent en fait ...

    en gros voici le code que je souhaite obtenir (en pseudo code puisque je n'y arrive pas )

    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
    /**
             * Retourne le nom de la class correspondant au type de traitement demandé
             * @param type Le type d'objet à traiter
             * @return Le nom de la classe
             */
    	private String getClassName(char type) {
    		switch(type){
    		case PROJ :
    			return "com.primavera.integration.client.bo.object.ProjectCode";
    		case ACT :
    			return "com.primavera.integration.client.bo.object.ActivityCode";
    		case RES :
    			return "com.primavera.integration.client.bo.object.ResourceCode";
    		default :
    			return null;
    		}
    	}// getClassName
     
     
    traitement(char type){
         Class classeCode = Class.forName(getClassName(type));
     
         Method loadXXX = classeCode.getMethod("load", new          Class[]{Class.forName("com.primavera.integration.client.Session"),
               Class.forName("java.lang.Object[]"),
               Class.forName("com.primavera.common.value.ObjectId")});
     
         Object[] params = {session,
                                    new String[]{"CodeValue","Description","CodeTypeName","ParentObjectId"}, 
                                    ids};
     
         listeCodes = (BOIterator) loadXXX.invoke(classeCode.newInstance(),params);
         while(listeCodes.hasNext()){
                classCode code = (classeCode) listeCodes.next();
                String codeValue = code.getCodeValue();
                String codeTypeName = code.getCodeTypeName();
                ...
         }
    }//traitement

  9. #9
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par in
    bon je vais éditer le premier message pour indiquer ce qui est différent en fait ...
    Le code utilisant la reflection me semble tout à fait correcte !
    Je ne comprend pas ce que tu n'arrives pas à faire (quel partie du code te pose problème ?)...

    a++

  10. #10
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Bon en fait comme je modifie au fur et à mesure, je n'ai pas encore testé. en fait ça ne compile pas (Enfin Eclipse m'indique des erreurs).

    L'appel de la méthode à l'air correct (pour Eclipse tout du moins)
    par contre c'est au niveau de mes cast. je ne sais pas du tout comment faire ...

    j'aimerais faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    classeCode code = (classeCode) listeCodes.next();
     // pour remplacer 
     // ActivityCode code = (ActivityCode) listeCodes.next();
    mais bon il me dit que classeCode ne peut pas être résolue comme un type
    du coup je bidouille (getClass ...) mais je n'y arrive pas

    any idea ?

  11. #11
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Ok je crois que j'ai compris : C'est le bout de code à l'intérieur du while qui te pose problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while(listeCodes.hasNext()){
        classCode code = (classeCode) listeCodes.next();
        String codeValue = code.getCodeValue();
        String codeTypeName = code.getCodeTypeName();
        ...
         }
    Ce qui te gène c'est que tu ne peux pas faire de cast comme cela, et que les méthode getCodeValue(), getCodeTypeName() et eventuellement d'autre sont défini dans tes trois classes mais n'appartiennent pas à un interface/classe commune...

    C'est bien çà ???


    Si la réponse est oui je pense qu'il doit y avoir un moyen de faire cela avec les Proxy et les InvocationHandler (voir : http://blog.developpez.com/index.php...&c=1&tb=1&pb=1 )

    a++

  12. #12
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Citation Envoyé par adiGuba
    Ok je crois que j'ai compris : C'est le bout de code à l'intérieur du while qui te pose problème
    ...
    Ce qui te gène c'est que tu ne peux pas faire de cast comme cela, et que les méthode getCodeValue(), getCodeTypeName() et eventuellement d'autre sont défini dans tes trois classes mais n'appartiennent pas à un interface/classe commune...

    C'est bien çà ???
    oui exactement !

    je regarde ça immédiatement.

    Au fait est ce que mon choix est justifié ou alors d'habitude on fait ça avec le switch ?

    par ce que moi je vais peut etre partir de ce projet et je voudrais laisser qqchose de simple à maintenir (pas de redondance de code).

    Là j'ai peur de compliquer les choses ... enfin bon en meme temps j'aurais appris qqchose


    [EDIT] A vrai dire, je ne vois pas trop comment adapter ton exemple ... enfin je vais cherché un peu plus sur google sur les InvocationHandler.

    merci

  13. #13
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par in
    Au fait est ce que mon choix est justifié ou alors d'habitude on fait ça avec le switch ?
    Ton choix peut être justifié dans ton cas. Toutefois il semble que tes classes ProjectCode, ActivityCode, etc. soit mal conçus car elle aurait dû implémenter une interface commune : cela aurait grandement simplifié le travail !!!

    Citation Envoyé par in
    Là j'ai peur de compliquer les choses ... enfin bon en meme temps j'aurais appris qqchose
    C'est un peu complexe mais cela peut être intérressant même si tu ne l'utilisera pas.


    Donc on souhaite créer une interface qui regroupera les méthodes communes à ces différentes classes (mais différentes puisqu'il n'y a aucun lien entre elles).

    Cela pourrait donner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    interface InterfaceCode {
        public String getCodeValue();
        public String getCodeTypeName();
        // etc.
    }
    Et on va se créer une classe utilitaire qui va générer automatiquement des classes implémentant cette interface, et qui renverront les appels de méthodes vers les méthodes "correspondantes" (même nom mêmes paramètres) de la classe.

    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
    class ReflectiveInterfaceCode implements InvocationHandler {
     
        private final Object instance;
        private final Class type;
     
        /**
         * Constructeur privée
         * @param instance L'instance de l'objet.
         */
        private ReflectiveInterfaceCode(Object instance) {
            this.instance = instance;
            type = this.instance.getClass();
        }
     
        /**
         * Retourne une interface qui appelle la méthode correspondante sur l'objet 'instance'.
         */
        public static InterfaceCode asInterface(Object instance) {
            return (InterfaceCode) Proxy.newProxyInstance(
                    instance.getClass().getClassLoader(), // ClassLoader
                    new Class[]{InterfaceCode.class},    // L'interface implémentée
                    new ReflectiveInterfaceCode(instance) );
        }
     
        /**
         * Cette méthode est appelé pour tous les appels de méthode sur l'interface retourné
         * par la méthode asInterface(). Elle se contente de renvoyer les appels de méthodes
         * vers l'objet en instance. Si la méthode n'existe pas cela provoquera une exception.
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
            // On est obligé de rechercher la méthode, car même si
            // le nom correspond la signature est différente car elles
            // n'appartiennent pas à la même interface/classe.
            Method m = this.type.getMethod(
                    method.getName(),
                    method.getParameterTypes() );
     
            return m.invoke(this.instance, args);
        }
    }
    Le constructeur est privée car on ne doit pas utiliser cette classe directement, mais utiliser la méthode statique asInterface() qui renvoit une interface pour l'objet instance. Tous les appels de méthode sur l'interface seront "traduit" vers des appels à la méthode invoke() de cette classe avec les bons paramètres. Il suffit donc dans cette dernière de renvoyer les appels vers la vrai méthode de l'instance.


    Ainsi le code a utiliser dans ta boucle while est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            while(listeCodes.hasNext()){
                InterfaceCode xCode = ReflectiveInterfaceCode.asInterface( listeCodes.next() );
                String codeValue = xCode.getCodeValue();
                String codeTypeName = xCode.getCodeTypeName();
                // ...
            }



    Sinon deux remarques sur le reste de ton code :
    • Si les méthodes load() sont static, le premier paramètre de la méthode invoke() lors de l'appel doit être null :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      listeCodes = (BOIterator) loadXXX.invoke(null,params);
    • Tu peux utiliser Session.class à la place de Class.forName("...Session")
    a++

  14. #14
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Ok merci beaucoup !!

    sans ces explications j'étais mal. par contre j'ai un peu honte, tu as tout fait pour moi ...

    un grand merci.

    je teste demain, mais pour l'instant ça compile !!

    merci encore !

  15. #15
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Youpi !

    c'est bon ça fonctionne, je l'ai également adapté à un autre endroit... ça me simplifie grandement les choses. Et une fois qu'on a compris, c'est pas si complexe.

    Enfin, je n'y aurais jamais pensé tout seul. Franchement respect pour ton expertise en Java.

    Donc voilà, je clos le sujet. Avec en plus l'agréable sensation d'avoir appris quelque chose d'utile.

    merci encore.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 25/03/2008, 12h31
  2. Réponses: 2
    Dernier message: 02/07/2007, 17h19
  3. Réponses: 1
    Dernier message: 15/08/2006, 13h58
  4. Utiliser une image à la place du curseur par défaut
    Par nice dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 11/12/2005, 23h15

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