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

API standards et tierces Java Discussion :

[REFLEXION] Connaitre toutes les classes qui implémentent une interface


Sujet :

API standards et tierces Java

  1. #1
    Membre expérimenté
    [REFLEXION] Connaitre toutes les classes qui implémentent une interface
    Bonjour,
    Quel est selon vous le meilleur moyen de trouver l'ensemble des class implémentant une interface ?
    La seule chose connu serait que ces classe se trouvent dans un package bien spécique.

    Voici un peu ce que je cherche à faire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    Liste<Class> monType = ClassUtilitie.findSubClass(mon.package.MonInterface.class);


    merci

  2. #2
    Expert éminent sénior
    Salut,


    Il n'y a aucun moyen de faire cela via la reflection : ce serait bien trop lourd car il faudrait charger toutes les classes du CLASSPATH...

    Si ces classes ne sont présente que dans un seul et unique package à la rigueur tu pourrais faire cela "à la main" en chargeant les classes une à une mais ce n'est pas pratique (on ne peut même pas connaitre toutes les classes d'un même package).


    Pourquoi as-tu besoin de cela ?

    a++
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  3. #3
    Membre expérimenté
    Merci,
    J'ai déjà fait ce genre de chose. En fait je parcourais tous les fichier classe d'un répertoire, je chargeait la classe puis je vérifiait qu'elle implémentaient la classe mère. Ca fonctionne mais mon code n'est pas top je trouve et dans certains cas ça ne fonctionne pas.

    J'utilise ce chargement dynamique pour avoir un système de plugin dans mon application. J'aurais espéré que les nouvelles version de java me facilite la tâche

  4. #4
    Expert éminent sénior
    Avec Java 6 il y a la notion de service qui pourrait être une aternative au scan des répertoires...


    Un "service" correspond à une interface (ou une classe abstraite), et les "service provider" sont des implémentations de cette interface (ou de cette classe abstraite).

    Toutes les implémentations doivent être déclarées dans un fichier spécifique dans le répertoire META-INF/services...

    A partir de là, la classe ServiceLoader peut te retrouver toutes les implémentation ainsi déclarées...


    Par exemple, tu as une interface com.maboite.MonInterface, et trois implémentation spécifique com.maboite.MonImpl, com.monautreboite.MaClasse et com.monautreboite.souspackage.MonAutreImpl

    Tu devras donc avoir un fichier META-INF/services/com.maboite.MonInterface qui contiendra les lignes suivantes :
    Code X :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    com.maboite.MonImpl
     com.monautreboite.MaClasse
    com.monautreboite.souspackage.MonAutreImpl



    Ensuite, il ne te reste plus qu'à utiliser la méthode load() qui analysera ce fichier et chargera ces classes :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    for (MonInterface interface : ServiceLoader.load(MontInterface.class)) {
         ...
    }



    Bien sûr chacun de tes jar ou de tes répertoires du classpath peuvent avoir un de ces fichiers, et ils seront tous lus...


    Tu ne dois surement pas utiliser Java 6 mais ce n'est pas vraiment très compliqué à codé : il suffit d'utiliser la méthode getResources(java.lang.String) du ClassLoader pour retrouver tous les fichiers du même nom dans les divers éléments du classpath...

    ensuite ce n'est que lecture de fichier + reflection simple...


    Je dois avoir un code de ce genre quelque part... si je le retrouve je le posterais...

    a++
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  5. #5
    Membre expérimenté
    Ca a l'aire trop fort cette histoire de service ! Il sort quand Java6 ?
    Si je comprend bien il va falloire que je parcours encore mes pakages et faire tout ça à la mimine....

    merci adiGuba

  6. #6
    Expert éminent sénior
    Citation Envoyé par narmataru
    Ca a l'aire trop fort cette histoire de service ! Il sort quand Java6 ?
    Il devrait sortir d'ici la fin de l'année...


    Citation Envoyé par narmataru
    Si je comprend bien il va falloire que je parcours encore mes pakages et faire tout ça à la mimine....
    Non tu peux très bien coder cela : ce n'est pas bien compliquée...

    Cela pourrait donner ceci (code Java 5.0 à adapter au cas où) :
    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
        public static <T> Iterable<Class<? extends T>> searchServices(Class<T> abstractType, ClassLoader loader) throws IOException, ClassNotFoundException, ClassCastException {
     
            // Nom des fichiers contenants les "services" :
            String name = "META-INF/services/" + abstractType.getName();
     
            // Liste contenant le résultat
            Set<Class<? extends T>> resultSet = new HashSet<Class<? extends T>>();
     
            // Pattern permettant de supprimer les commentaires :
            Pattern pattern = Pattern.compile("#.*$");
     
     
            // On parcours la liste des fichiers 'services' :
            Enumeration<URL> resources = loader.getResources(name);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
     
                // On lit le fichier ligne par ligne
                BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
                try {
                    String line;
                    while ( (line=reader.readLine()) != null ) {
                        // On supprime tout ce qui suit le # (commentaire)
                        line = pattern.matcher(line).replaceAll("").trim();
                        if (!"".equals(line)) {
                            // On charge la classe :
                            Class<?> classType = loader.loadClass(line);
     
                            // Et on l'ajoute dans la liste des résultats
                            // (ClassCastException en cas de type incorrect)
                            resultSet.add( classType.asSubclass(abstractType) );
                        }
                    }
                } finally {
                    reader.close();
                }
            }
     
            return resultSet;
        }
    Note : en cas d'erreur l'exception est remonté à la méthode appellante. Il serait surement utile d'adapter cela pour éviter ce type de problème

    a++
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  7. #7
    Membre expérimenté
    Ouha un grand merci, je vais regarder et tester tout ça

  8. #8
    Membre expérimenté
    Merci beaucoup adiGuba ça fonctionne

###raw>template_hook.ano_emploi###