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 :

[Reflection] Recherche d'un méthode avec des arguments de type dérivé


Sujet :

Langage Java

  1. #1
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut [Reflection] Recherche d'un méthode avec des arguments de type dérivé
    Bonjour,

    Je cherche à faire de la réflection de méthode avec des arguments de type dérivé.

    J'utilise la méthode getMethod(...) de la classe Class.

    Je veux retrouver le type de retour de la méthode println() de la classe java.io.PrintStream dont l'argument est de type java.util.Comparator.

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Class type = java.io.PrintStream.class;
    String nom = "println";
    Class[] args = new Class[1];
    args[0] = java.util.Comparator.class;
     
    try {
    	Method methode = type.getMethod(nom, args);
    	type = methode.getReturnType();
    } catch (SecurityException e) {
    	e.printStackTrace();
    } catch (NoSuchMethodException e) {
    	e.printStackTrace();
    }

    Il devrait me retrouver la méthode PrintStream.println(Object) mais il n'en est rien, j'ai plutôt une exception... :
    java.lang.NoSuchMethodException: java.io.PrintStream.println(java.util.Comparator)
    at java.lang.Class.getMethod(Unknown Source)
    at fr.societe.projet.MaClasse.maMethode(MaClasse.java:XXX)
    at [...]
    Comment remédier à ce problème sans avoir à tester toutes les méthodes héritées et implémentées ? (Surtout que ça peut devenir compliqué à partir de deux arguments)

    [EDIT]
    J'ai également lu ce sujet : http://www.developpez.net/forums/d77...introspection/
    ... qui correspond à mon problème. Cependant, j'ai une remarque sur le post #5 : A priori, un appel ambigu ne peut pas être fait en Java, une erreur de compilation est censée être retournée (à moins que ce ne soit qu'un simple avertissement ).

    Bref, la question est du coup restée en suspens.
    [/EDIT]

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    333
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 333
    Points : 295
    Points
    295
    Par défaut
    Salut,

    Pas de solution simple à ma connaissance ...

    Tu peux partir dans l'analyse d'héritage et implémentation, mais ça peut être complexe

    sinon la méthode empirique bourrin, tu récupères celle qui s'exécute

    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
    	public static void main(String[] args2) {
    		Class type = java.io.PrintStream.class;
    		String nom = "println";
    		Class[] args = new Class[1];
    		args[0] = java.util.Comparator.class;
     
    			Method[] methods = type.getMethods();	
    			for (Method method : methods) {
    			boolean ok = true;
    				try {
    					method.invoke(type, args);
    				} catch (IllegalArgumentException e) {
    					ok = false;
    				} catch (IllegalAccessException e) {
    					ok = false;
    				} catch (InvocationTargetException e) {
    					ok = false;
    				}
    				if (ok){
    					System.out.println(method);
    				}
    			}
    	}
    [edit]
    En fait ce code ne fonctionne pas invoke s'applique que des instances d'objets, on peut en récupérer avec newInstance mais ce n'est pas vraiment généralisable (Interface ... ) puis à y repenser ça ne me semble pas une bonne appproche
    [/edit]
    Bon le code peut être amélioré mais c'est une piste ....

    Bon courage

  3. #3
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    OK, merci, c'est bien ce qui m'inquiétait.

    Perso, j'ai fait ça en solution d'"urgence" :
    Code Java : 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
    Method[] methodes = type.getMethods();
    for (Method methode : methodes) {
    	if (methode.getName().equals(nom)) {
    		Class[] parametres = methode.getParameterTypes();
    		if (parametres.length == arguments.length) {
    			int j = 0;
    			boolean idem = true;
    			while (idem && j < parametres.length) {
    				Class parametre = parametres[j];
    				Class argument = arguments[j];
    				if (argument.isInstance(parametre)) {
    					idem = false;
    				}
    				j++;
    			}
    			if (idem) {
    				type = methode.getReturnType();
    				break;
    			}
    		}
    	}
    }
    Je déteste les break jetés au loup comme ça. Il faut juste que je vérifie qu'il me sorte bien de la boucle for.

    Penses-tu que c'est encore optimisable ?

  4. #4
    Membre expérimenté Avatar de herve91
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 282
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 282
    Points : 1 608
    Points
    1 608
    Par défaut
    Les méthodes PrintStream.println() acceptent en entrée un boolean, char, ..., Object, String, long.
    par laquelle es-tu intéressé ?
    Concernant le paramètre parameterTypes de la méthode Class.getMethod(), la Javadoc dit :
    The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order
    Il te faudra procéder par essais et erreurs jusqu'à trouver la bonne méthode (ou non) mais ça risque d'être un peu compliqué par le jeu des interfaces héritées ou implémentées...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class Test implements I1, I2 ... 
    interface I2 extends I1 ...
     
    void method(I1 i) {
    } 
    void method(I2 i) {
    }
    devrait te renvoyer method(I2) si tu l'appelles avec Test.class

  5. #5
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Vu comment fonctionne Java, si je met en paramètre un Comparator à la méthode println, il est censé me prendre la méthode qui a comme paramètre Object. Par contre, si je met un String, il est censé prendre la méthode avec String. Je pensais qu'il y avait une résolution du type, si j'appelle la méthode avec type1, renvoie moi laquelle sera réellement appelée.

    Dans tous les cas, une méthode avec un même nom dans une classe n'est pas censée renvoyer deux types différents. Au pire, on n'en mourra pas pour ce à quoi ça sert... (voir suite).

    Le but de cet affaire est d'ajouter une règle PMD (ah ouais, le truc pas compliqué du tout), je procède par résolution de type car ce qui a été fait dans PMD au niveau de la résolution de type pour certains types expressions, il y a de jolis TODO "C'est un peu compliqué alors on l'a pas fait", j'adore .

    Pour la curiosité, la règle PMD consiste à détecter que chaque catch contient un appel à un logger particulier avec la méthode log de celui-ci. Mais pour cela, il faut résoudre l'ensemble de la ligne avant de dire si on a bien le bon logger.

    Plus d'infos : Site officiel de PMD

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    333
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 333
    Points : 295
    Points
    295
    Par défaut
    Il y a ce post sur le sujet avec la classe utilitaire qu'il faut (peut être à remettre à jour ... date de 2003 )

    http://forums.sun.com/thread.jspa?th...686&forumID=31

    Par contre je comprends pas pourquoi tu utilises un logger particulier pour chaque catch

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par BiM Voir le message
    Vu comment fonctionne Java, si je met en paramètre un Comparator à la méthode println, il est censé me prendre la méthode qui a comme paramètre Object.
    Pas entièrement vrais. C'est comme ça que fonctionne le compilateur, la JVM, elle, travaille uniquement avec les type déclarés (sinon bonjour les perfs). Ainsi, prenons exemple les code suivants, dans deux fichiers java distincts.

    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
     
    public class Test1 {
    /* 
        public void maMethode(java.util.ArrayList l){
            System.out.println("Méthode avec ArrayList");
        }
        public void maMethode(String s){
            System.out.println("Méthode avec String");
        } */
     
       public void maMethode(java.util.List l){
            System.out.println("Méthode avec List");
        }
        public void maMethode(Object o){
            System.out.println("Méthode avec Object");
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class Test{
        public static void main(String[] argv){
            Test1 t = new Test1();
            t.maMethode("String");
            t.maMethode(new java.util.ArrayList());
        }
    }
    On a tout naturellement comme sortie
    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ /usr/local/jdk1.6/bin/java Test
    Méthode avec Object
    Méthode avec List
    $

    Maintenant, on modifie Test1 et on le recompile sans recompiler Test:
    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
     
    public class Test1 {
     
        public void maMethode(java.util.ArrayList l){
            System.out.println("Méthode avec ArrayList");
        }
        public void maMethode(String s){
            System.out.println("Méthode avec String");
        } 
       /*
       public void maMethode(java.util.List l){
            System.out.println("Méthode avec List");
        }*/
        public void maMethode(Object o){
            System.out.println("Méthode avec Object");
        }
    }
    La sorti est alors la suivante:
    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ /usr/local/jdk1.6/bin/java Test
    Méthode avec Object
    Exception in thread "main" java.lang.NoSuchMethodError: Test1.maMethode(Ljava/util/List;)V
    	at Test.main(Test.java:5)
    $
    On vois que, dans Test, c'est bien respectivement Object et List qui sont cherchés, pas String et ArrayList

  8. #8
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Citation Envoyé par LittleBean Voir le message
    Il y a ce post sur le sujet avec la classe utilitaire qu'il faut (peut être à remettre à jour ... date de 2003 )

    http://forums.sun.com/thread.jspa?th...686&forumID=31

    Par contre je comprends pas pourquoi tu utilises un logger particulier pour chaque catch
    Merci pour vos réponses, je crois que je vais rester avec ce que j'ai fait, ça suffit amplement.

    Pour répondre à ta question, quand tu travailles sur des applications sensibles (et même sur des non sensibles, il est mieux que chaque trace soit regroupée et que chaque exception soit tracée (au cas où elle nous poserait problème en production)). Cela permet d'éviter d'avoir des sorties en sysout, d'autres en syserr, d'autres dans un logger A et d'autres dans un logger B et de ne pas s'y retrouver !

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par BiM Voir le message
    Merci pour vos réponses, je crois que je vais rester avec ce que j'ai fait, ça suffit amplement.

    Pour répondre à ta question, quand tu travailles sur des applications sensibles (et même sur des non sensibles, il est mieux que chaque trace soit regroupée et que chaque exception soit tracée (au cas où elle nous poserait problème en production)). Cela permet d'éviter d'avoir des sorties en sysout, d'autres en syserr, d'autres dans un logger A et d'autres dans un logger B et de ne pas s'y retrouver !
    Cette règle PMD est un peu brutale En l'occurence, il est tout aussi propre et courant de repropager plus haut l'exception, éventuellement wrappée comme cause d'un autre, sinon c'est vite les fichiers de log explosifs (il est très courrant d'avoir des excepton dans le cadre d'un fonctionnement normal), si tu génère une exception et que tu la loggue trois vois à cause de la repropagation toutes les 10 seconde, à 2k de log par exception, tu génère 51M de logs par jour

    Maintenant, évidement, si tu fais se taire les logguers en temps normal, c'est une autre chose :p

  10. #10
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Cette règle PMD est un peu brutale En l'occurence, il est tout aussi propre et courant de repropager plus haut l'exception, éventuellement wrappée comme cause d'un autre, sinon c'est vite les fichiers de log explosifs (il est très courrant d'avoir des excepton dans le cadre d'un fonctionnement normal), si tu génère une exception et que tu la loggue trois vois à cause de la repropagation toutes les 10 seconde, à 2k de log par exception, tu génère 51M de logs par jour

    Maintenant, évidement, si tu fais se taire les logguers en temps normal, c'est une autre chose :p
    Au vu des applis concernées, la règle est plutôt utile car les exceptions ne sont jamais "throwé", bref, la règle peut être ignorée au pire

  11. #11
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    333
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 333
    Points : 295
    Points
    295
    Par défaut
    Pour répondre à ta question, quand tu travailles sur des applications sensibles (et même sur des non sensibles, il est mieux que chaque trace soit regroupée et que chaque exception soit tracée (au cas où elle nous poserait problème en production)). Cela permet d'éviter d'avoir des sorties en sysout, d'autres en syserr, d'autres dans un logger A et d'autres dans un logger B et de ne pas s'y retrouver !
    Je ne remets pas en cause l'utilisation de logger

    Je me demandais ce que tu entendais par :
    que chaque catch contient un appel à un logger particulier
    Tu fais une surcouche de ton logger avec une méthode paramétrée par type d'exception ?


    Pour ta règle pmd pourquoi ne pas simplement vérifier que le catch n'est pas vide ? Si ce n'est pas vide le développeur y a 'réfléchi' ... donc ça devrait pas être du n'importe quoi non ?

  12. #12
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Non, il y a un appel spécifique au logger, mais pas un par type. Cependant, des fois ils sont vides, des fois ils contiennent un printStackTrace, un sysout ou un syserr, d'autres fois une (ou plusieurs) action(s) diverse(s) et parfois, le logger est bien appelé...

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

Discussions similaires

  1. Démarrer un service avec des arguments
    Par erlou dans le forum VBScript
    Réponses: 1
    Dernier message: 24/07/2007, 12h03
  2. Réponses: 1
    Dernier message: 08/03/2007, 10h55
  3. set_terminate : gestionnaire avec des arguments
    Par Patriarch24 dans le forum C++
    Réponses: 4
    Dernier message: 28/10/2006, 13h08
  4. Lancer un programme avec des arguments via IE...
    Par petozak dans le forum Général Conception Web
    Réponses: 6
    Dernier message: 24/03/2006, 11h51
  5. Réponses: 3
    Dernier message: 21/03/2006, 10h37

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