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 :

Charger dynamiquement une classe qui n'est pas dans un jar


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut Charger dynamiquement une classe qui n'est pas dans un jar
    Bonjour,

    J'ai regardé le tutoriel sur les plugins : http://vincentlaine.developpez.com/t.../java/plugins/

    J'ai vu que l'on pouvait charger en mémoire une classe qui n'est pas dans le classpath de l'application.
    Cependant, l'exemple est fait avec une classe qui se trouve à l'intèrieur d'un jar.

    Je voudrais pouvoir charger une classe juste à partir de son emplacement (cette class ne se trouve pas dans un jar).

    Avez vous un exemple à me donner sur la façon de faire, un tutoriel ...

    Merci d'avance

  2. #2
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Points : 4 314
    Points
    4 314
    Par défaut
    Je ne me suis jamais posé la question, donc je ne sais pas faire.

    Ceci dit, si tu veux réussir à coup sûr, tu peux appliquer la méthode "se ramener à un cas connu":

    Hypotèses:
    - tu sais que ça fonctionne si la classe est dans un jar
    - tu disposes d'une classe dont tu connais le chemin, mais en dehors d'un jar

    Solution:
    - tu compresses cette classe dans un fichier zip (via une API qui fera le boulot à ta place)
    - tu renommes ce fichier en jar
    - tu es ramené au cas connu => ça fonctionne!

  3. #3
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    Le problème n'est pas que je ne réussis pas à avoir ma class dans un jar.

    Le problème c'est que je ne veux pas avoir ma class dans un jar.

    Ce que tu me proposes c'est de créer un jar. En plus tu le fais d'une manière très complexe alors qu'il y a bien plus simple. (Un clic sur le bouton compiler dans un IDE ou une ligne de commande suffit)

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Points : 191
    Points
    191
    Par défaut
    Si t'as un peu compris le code du lien de ton message.
    C'est à peu pret la même chose.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    File f = new File("c:\\le_rep_de_ma_classe\\maClassACharger.class")
    URL urlDeMonFichierLocal =  f.toURL();
    ClassLoader loader = new URLClassLoader(new URL[] {urlDeMonFichierLocal}); 
    Class theLoadedClazz = Class.forName("monpackage.MaClasse" ,true, loader);
    // Voila
    // Par exemple
    theLoadedClazz.newIntance();

  5. #5
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    Merci !
    Apparement toURL est depracated donc ça donnerais ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    try{
        URL urlDeMonFichierLocal =  new URL("file://c:/le_rep_de_ma_classe/maClassACharger.class");
        ClassLoader loader = new URLClassLoader(new URL[] {urlDeMonFichierLocal}); 
        Class theLoadedClazz = Class.forName("monpackage.MaClasse" ,true, loader);
     
        theLoadedClazz.newInstance();
     
    }catch(MalformedURLException ex){System.out.println("MalformedURLException");
    }catch(ClassNotFoundException ex){System.out.println("ClassNotFoundException");
    }catch(InstantiationException ex){System.out.println("InstantiationException");
    }catch(IllegalAccessException ex){System.out.println("IllegalAccessException");}
    Excusez de mon faible niveau, mais je me demande comment faire pour accéder au méthodes de cette classe chargée...

  6. #6
    Expert éminent sénior


    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    7 856
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 7 856
    Points : 34 380
    Points
    34 380
    Par défaut
    Citation Envoyé par rastakouair Voir le message
    Excusez de mon faible niveau, mais je me demande comment faire pour accéder au méthodes de cette classe chargée...
    A moins d'avoir formalisé un contrat dans une interface qui serait elle dans le classpath, tu peux essayer la Reflection : http://ricky81.developpez.com/tutori...pi/reflection/

    Mais peut-être y-a-t-il un moyen plus élégant si tu nous détailles tes contraintes ?

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Points : 191
    Points
    191
    Par défaut
    Je te conseille de te documenter sur la reflexivité.
    Par contre en terme de conception, si tu utilises une logique de plugin, ça veut dire que la classe de ton plugin implemente une interface bien définit qui elle n'est pas chargé dynamiquement.

    Par exemple tu as ton programme qui utilise l'interface suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    interface Dessinateur {
      void dessinerRond (int x, int y, int rayon, Graphics g);
      void dessinerCarre (int x, int y, int cote, Graphics g);
      void dessinerLigne (int x1, int y1, int x2, int y2, Graphics g);
    }
    ton programme sera comme ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Dessinateur dessinateur = null;
    URL urlDeMonPlugin3D =  new URL("c:/le_rep_de_ma_classe/Dessinateur3D.class");
    URL urlDeMonPlugin2D =  new URL("c:/le_rep_de_ma_classe/Dessinateur3D.class");
    ClassLoader loader = new URLClassLoader(new URL[] {urlDeMonPlugin3D, urlDeMonPlugin2D}); 
    Class effet3DClazz = Class.forName("monpackage.Dessinateur3D" ,true, loader);
     
    dessinateur = effet3DClazz.newInstance();
    dessinateur.dessinerRond (x, y, rayon, g); 
    // Maintenant un carre sans effet 3D mais en classiq ue 2D
     
    Class effet2DClazz = Class.forName("monpackage.Dessinateur3D" ,true, loader);
    dessinateur = effet2DClazz.newInstance();
    dessinateur.dessinerCarre(x,y,cote, g);
    Le plus élégant c'est d'utliser une factory
    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
     
    public class DessinFactory {
       private URL urlDeMonPlugin3D =  new URL("c:/le_rep_de_ma_classe/Dessinateur3D.class");
       private URL urlDeMonPlugin2D =  new URL("c:/le_rep_de_ma_classe/Dessinateur2D.class");
       private ClassLoader loader = new URLClassLoader(new URL[] {urlDeMonPlugin3D, urlDeMonPlugin2D}); 
     
       public Dessinateur getInstance(String type)
       {
         if("3D".equals(type))
         {
            Class effet3DClazz = Class.forName("monpackage.Dessinateur3D" ,true, loader);
    	return effet3DClazz.newInstance();
         } else  // Par defaut implem 2D 
         {
            Class effet2DClazz = Class.forName("monpackage.Dessinateur2D" ,true, loader);
    	return effet2DClazz.newInstance();
         }
       }
    }
    Le prog principale
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    DessinFactory factory = new DessionFactory();
    Dessinateur dessinateur =  factory.getInstance("3D");
    dessinateur.dessinerRond (x, y, rayon, g); 
    // Maintenant un carre sans effet 3D mais en classique 2D
    dessinateur = factory.getInstance("2D");
    dessinateur.dessinerCarre(x,y,cote, g);

  8. #8
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    Merci , cependant j'ai une erreure de type...
    sur cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dessinateur = effet3DClazz.newInstance();
    dessinateur est de type Dessinateur
    effet3DClazz.newInstance() est de type Object



    Pareil pour le factory sur cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return effet3DClazz.newInstance();
    En effet, la fonction getInstanceest sencé retourner un élément de type Dessinateur alors que newInstance() renvoie un objet.


    phantomass >> as tu déjà testé ce que tu as proposé ? Car chez moi j'ai beau essayer ça ne fonctionne pas... J'ai une erreure de type : ClassNotFoundException

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Points : 191
    Points
    191
    Par défaut
    Non je n'ai pas testé le code, je l'ai écrit de tête juste pour te donner les piste.
    Les modifs à faire sont dut à des cast que j'ai oublié.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dessinateur = (Dessinateur) effet3DClazz.newInstance();
    return (Dessinateur) effet3DClazz.newInstance();
    Sans vouloir t'offenser , j'ai l'impression que tu t'attaques à un gros morceau alors que t'as peut-être encore quelques lacunes sur les bases du langages Java.

  10. #10
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    Tu ne m'offences pas du tout, je sais qu'il y a certaines bases que je n'ais pas
    Ma méthode n'est sûrement pas la bonne, mais j'essaye d'apprendre le Java au fur et à mesure du développement de mon projet

    Merci pour ta solution, je n'y avais pas pensé. Il n'y a donc plus d'erreure de type maintenant.

    Par contre, il y a toujours une erreure de type ClassNotFoundException :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    URL urlDeMonFichierLocal =  new URL("file://E:/maclass.class");    //Pas d'erreure ici
    ClassLoader loader = new URLClassLoader(new URL[] {urlDeMonFichierLocal});    //Pas d'erreure ici non plus 
    Class theLoadedClazz = Class.forName("monpackage.maclass" ,true, loader);       //Erreure de type ClassNotFoundException
    L'erreur renvoie au code suivant de la classe URLClassLoader :

    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
    protected Class<?> findClass(final String name)
    	 throws ClassNotFoundException
        {
    	try {
    	    return (Class)
    		AccessController.doPrivileged(new PrivilegedExceptionAction() {
    		    public Object run() throws ClassNotFoundException {
    			String path = name.replace('.', '/').concat(".class");
    			Resource res = ucp.getResource(path, false);
    			if (res != null) {
    			    try {
    				return defineClass(name, res);
    			    } catch (IOException e) {
    				throw new ClassNotFoundException(name, e);
    			    }
    			} else {
     /* C'est ici que l'erreure est détectée*/
    			    throw new ClassNotFoundException(name);
     /* C'est ici que l'erreure est détectée*/
    			}
    		    }
    		}, acc);
    	} catch (java.security.PrivilegedActionException pae) {
    	    throw (ClassNotFoundException) pae.getException();
    	}
        }
    Je suppose que URLClassLoader est prévu pour charger une classe à partir d'un jar. Donc à priorit je n'ais pas le choix...

  11. #11
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    En fait je viens de me rendre compte que ça n'as pas de sens ce que j'essai de faire.

    Tout simplement parceque ce n'est pas possible !
    En effet, pour créer ma class, il faut que j'implémente mon interface. Ca veut donc dire que j'ai au minimun 2 classes (mon interface + ma classe appelant l'interface)
    Donc je suis obligé de regrouper les 2 dans un jar.


  12. #12
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Points : 191
    Points
    191
    Par défaut
    Je ne sais pas trop ce que tu cherches à faire, mais en terme de composant quand on utilise une stratégie de plugin pour une appli, pour faire compliqué pour un cas simple on dira :
    - Tu as 1 jar pour ton appli (appli.jar)
    - Tu as 1 jar qui définit tes interfaces (interfaces.jar). Donc le jar de ton appli en dépend à l'exécution.
    - Et tu as un ensemble d'implémentations de plugin qui peuvent êtres créés par un tiers à condition que tu lui fournissent interfaces.jar

    Ensuite il y a une convention déterminant ou doivent se trouver le(s) jar/classes de ton plugin pour que ton appli puissent les utiliser dynamiquement.
    Par exemple la convention sur Eclipse pour les plugins : il sont décrit dans un fichier feature.xml dans une sous arborescence du répertoire features.
    Les jars et/ou classes sont situées dans le répertoire plugins.

  13. #13
    Membre à l'essai
    Inscrit en
    Décembre 2007
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 47
    Points : 24
    Points
    24
    Par défaut
    En effet c'est pas bête !
    J'avais commencé par mettre mon interface dans tous mes plugins plus dans mon appli principale !
    Je vais de ce pas faire un jar séparé pour mon interface.

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

Discussions similaires

  1. Barre de progression d'une macro qui n'est pas dans un module
    Par Boris_Gem dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 20/10/2010, 10h47
  2. Réponses: 1
    Dernier message: 31/08/2009, 17h18
  3. Réponses: 3
    Dernier message: 01/06/2006, 16h26
  4. Trouver une valeur qui n'est pas dans un champ
    Par eric41 dans le forum Requêtes
    Réponses: 6
    Dernier message: 16/05/2006, 16h48
  5. lien dessus une images qui n'est pas en background
    Par tiyolx dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 04/03/2006, 18h40

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