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 :

chargement de librairies *.jar avec ClassLoader


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Inscrit en
    Juillet 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 4
    Par défaut chargement de librairies *.jar avec ClassLoader
    Bonjour,

    Je bloque depuis un moment sur un problème.

    J'ai implémenté mon propre ClassLoader afin d'utiliser une classe qui n'est pas dans mon projet.

    voici le code de mon ClassLoader :

    ------------------------------------------------------
    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
    public class MyClassLoader extends URLClassLoader
    { 
     
    	protected MyClassLoader(URL[] urls) {
    		super(urls); 
    	} 
     
    	protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 
     
    		System.err.println("[loadClass("+name+","+resolve+")]"); 
    		return super.loadClass(name,resolve); 
    	}
     
    	protected Class findClass(String name) throws ClassNotFoundException { 
     
    		byte[] b = loadClassData(name); 
     
    		return defineClass(null, b, 0, b.length); 
    	} 
     
    	private byte[] loadClassData(String name) throws ClassNotFoundException { 
     
    		try { 
    			String myclassloader = "monRep/maclasse/";
    			String filename = myclassloader + name + ".class"; 
    			InputStream in = new FileInputStream(filename); 
    			byte[] data = new byte[in.available()]; 
     
    			in.read(data); 
    			in.close(); 
     
    			return data; 
     
    		} catch (FileNotFoundException x) { 
    			throw new ClassNotFoundException(name,x); 
    		} catch (IOException x) { 
    			throw new ClassNotFoundException(name,x); 
    		}
    	}
     
    }
    ----------------------------------------

    J'arrive à récupérer une instance de la classe qui m'intéresse.
    Mon problème est que cette classe s'appuie sur des librairies (poi.jar ...) qui sont contenues dans monRep/lib.
    J'ai pourtant chargé l'ensemble de ces librairies comme suit:

    --------------------------------------
    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
    String file = "monRep/lib/";
     
    File addonsDir = new File(file);
    File[] jars = addonsDir.listFiles(new FilenameFilter() {
    <div style="margin-left:40px">public boolean accept(File dir, String name) {
    	return name.endsWith(".jar");
    }</div>});
     
    List urls = new LinkedList();
    for (int i = 0; i < jars.length; i++) {[/INDENT]try {
    	URL url = jars[i].toURL();
    	urls.add(url);
    	} catch (MalformedURLException e) {}
    }
     
    MyClassLoader loader = new MyClassLoader(((URL[])urls.toArray(new URL[urls.size()])));
    Class classe = loader.loadClass("MaClasse");
     
    Method method = classe.getMethod("myMethod", null);
    --------------------------------------

    Lorsque j'appelle une méthode de cette classe en utilisant method.invoke(), voici l'erreur qui se produit:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/poi/ss/usermodel/Workbook
    	at java.lang.Class.getDeclaredMethods0(Native Method)
    	at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
    	at java.lang.Class.getMethod0(Class.java:2670)
    	at java.lang.Class.getMethod(Class.java:1603)
    	at xls.AccessXls.main(AccessXls.java:59)
    Caused by: java.lang.ClassNotFoundException: org.apache.poi.ss.usermodel.Workbook

    En clair, il n'arrive pas à trouver les différentes classes contenues dans les librairies *.jar et utilisées par ma classe "MaClasse".

    Comment charger chacune des librairies dans le classpath?



    Merci Pour votre aide.

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    En effet, la jvm utilise par défaut le system class loader. Donc tu es obligé de charger les librairies externes au lancement de la jvm, il n'est absolument pas possible de faire autrement pour des raisons de sécurité.

  3. #3
    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
    tu surcharge findClass, ce qui fait que tu ignore complètement le comportement par défaut, ce qui fait que tu ne chargera absolument rien depuis les .jar référéncés dans tun url[]. Soit tu continue sur cette lancée et, si c'est pas le nom auquel tu t'attends (ou tu trouve pas), tu fait appel à super.findClass(), soit tu fait plus simple, tu rajoute à la liste des url[] le répetroire contenant ton .class dans une hierarchie correcte, et t'as pas de classloader custom à gérer.

    @verbose: faux, tu peux très bien ajouter tes propre classloader et y charger des classes, y a pas de raison. La plupart des systèmes de plugin utilisent ca poru éviter les conflits entre les plugins.

  4. #4
    Futur Membre du Club
    Inscrit en
    Juillet 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 4
    Par défaut
    Merci pour vos réponses.

    1 ------
    J'avais opté pour la seconde solution, càd charger le répertoire contenant mon *.class avec la liste des *.jar mais sans succès.

    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
     
    String myclassloader = "monRep/maclasse/";
    File addonsDir = new File(file);
    File[] jars = addonsDir.listFiles(new FilenameFilter() {
    public boolean accept(File dir, String name) {
    	return name.endsWith(".jar");
    	}
    });
    List urls = new LinkedList();
     
    urls.add(new File(myclassloader).toURL());
    for (int i = 0; i < jars.length; i++) {
    	try {
    		URL url = jars[i].toURL();
    		urls.add(url);
    	} catch (MalformedURLException e) {}
    }
    J'utilise le URLClassLoader pour charger mes librairies et le répertoire contenant ma classe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    URLClassLoader loader = new URLClassLoader(((URL[])urls.toArray(new URL[urls.size()])));
    Class classe = loader.loadClass("Maclasse");
    Il me renvoyé une erreur du type
    java.lang.ClassNotFoundException: maClasse
    ....
    ....

    Je ne comprends pas quand tu dis que je dois charger les librairies dans une hiérarchie correcte, n'est pas le cas?


    2 -----

    Je ne comprends quand tu dis:
    tu surcharge findClass, ce qui fait que tu ignore complètement le comportement par défaut, ce qui fait que tu ne chargera absolument rien depuis les .jar référéncés dans tun url[]".

    En quoi le fait de surcharger findClass() empêche le chargement des classes contenues dans les jar?


    J'avoue que quelque chose m'échappe.

    Merci d'avance.

  5. #5
    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
    tu crée un URLClassLoader qui pointe sur les .jar et, en plus, tu tente d'ajouter un comportement pour charger un .class précis. Le priblème c'est que le chargement du contenu des .jar se fera aussi par findClass(), mais tu désactive complètement ce comportement en mettant uniquement dedans la recherche de ton .class sans prendre en charge les .jar. Le résultat c'est que tes .jar servent à rien. Le mieux ca reste dans ton cas de faire ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    findClass(....)
      if (class == mon type bien particulier)
         je charge à la main
      sinon
         je fait super.findClass(.....) pour charger des .jar

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    @verbose: faux, tu peux très bien ajouter tes propre classloader et y charger des classes, y a pas de raison. La plupart des systèmes de plugin utilisent ca poru éviter les conflits entre les plugins.
    Je croyais que c'était impossible, ça tombe bien, je vais pouvoir utiliser cette possibilité dans mon projet perso

  7. #7
    Futur Membre du Club
    Inscrit en
    Juillet 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 4
    Par défaut
    Merci pour ton aide précieuse tchize_, j'arrive bien à charger ma classe ainsi que tous les jar.

    Mais j'ai un nouveau problème !!!

    En fait, l'ensemble des jars que je charge correspond au jar nécessaires à l'utilisation de la dernière version de poi.
    Lorsque je tente d'instancier une classe de poi.jar (qui s'appuie sur xmlbeans.jar), j'ai ce message d'erreur:

    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
    Caused by: java.lang.ExceptionInInitializerError
    	at org.apache.xmlbeans.impl.schema.BuiltinSchemaTypeSystem.fillInType(BuiltinSchemaTypeSystem.java:1025)
    	at org.apache.xmlbeans.impl.schema.BuiltinSchemaTypeSystem.<clinit>(BuiltinSchemaTypeSystem.java:223)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.apache.xmlbeans.XmlBeans.getNoType(XmlBeans.java:856)
    	at org.apache.xmlbeans.XmlBeans.<clinit>(XmlBeans.java:881)
    	at org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument$Factory.parse(Unknown Source)
    	at org.apache.poi.xssf.model.StylesTable.readFrom(StylesTable.java:103)
    	at org.apache.poi.xssf.model.StylesTable.<init>(StylesTable.java:92)
    	... 14 more
    Caused by: java.lang.RuntimeException: Installation Problem???  Couldn't load messages: Can't find bundle for base name org.apache.xmlbeans.impl.regex.message, locale fr_FR
    	at org.apache.xmlbeans.impl.regex.RegexParser.setLocale(RegexParser.java:88)
    	at org.apache.xmlbeans.impl.regex.RegexParser.<init>(RegexParser.java:78)
    	at org.apache.xmlbeans.impl.regex.ParserForXMLSchema.<init>(ParserForXMLSchema.java:28)
    	at org.apache.xmlbeans.impl.regex.RegularExpression.setPattern(RegularExpression.java:2996)
    	at org.apache.xmlbeans.impl.regex.RegularExpression.setPattern(RegularExpression.java:3009)
    	at org.apache.xmlbeans.impl.regex.RegularExpression.<init>(RegularExpression.java:2975)
    	at org.apache.xmlbeans.impl.regex.SchemaRegularExpression.<init>(SchemaRegularExpression.java:27)
    	at org.apache.xmlbeans.impl.regex.SchemaRegularExpression.<init>(SchemaRegularExpression.java:23)
    	at org.apache.xmlbeans.impl.regex.SchemaRegularExpression$1.<init>(SchemaRegularExpression.java:44)
    	at org.apache.xmlbeans.impl.regex.SchemaRegularExpression.buildKnownPatternMap(SchemaRegularExpression.java:43)
    	at org.apache.xmlbeans.impl.regex.SchemaRegularExpression.<clinit>(SchemaRegularExpression.java:38)
    	... 25 more
    et ce message d'erreur m'interpelle tout particulièrement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Caused by: java.lang.RuntimeException: Installation Problem???  Couldn't load messages: Can't find bundle for base name org.apache.xmlbeans.impl.regex.message, locale fr_FR

    Ce code fonctionne pourtant si je charge les librairies de manière classique.


    As tu une idéé ???

    Merci

  8. #8
    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
    tu peux nous montrer ton classloader actuel?

    Peut-être peux tu avant de faire tes appel à poi faire un Thread.currentTread().setContextClassLoader(tonClassloader).

    Certaines librairies utilisent le context classloader plutot que getClass().getClassLoader();

  9. #9
    Futur Membre du Club
    Inscrit en
    Juillet 2009
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 4
    Par défaut
    Bonjour,

    Malheureusement, cela ne règle pas le problème.
    Voici mon classloader:

    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
    42
    43
    44
     
     
    public class MyClassLoader extends URLClassLoader
    { 
     
    	protected MyClassLoader(URL[] urls) {
    		super(urls); 
    	} 
     
     
    protected Class findClass(String name) throws ClassNotFoundException { 
     
    		System.out.println("name == " + name);
    		if(name.equals("XlsTools"))
    		{
    			byte[] b = loadClassData(name); 
    			return defineClass(null, b, 0, b.length); 
    		}
    		else
    			return super.findClass(name);
     
    	}
     
    private byte[] loadClassData(String name) throws ClassNotFoundException { 
     
    		try { 
    			String myclassloader = "C:/myRep/";
    			String filename = myclassloader + name + ".class"; 
    			InputStream in = new FileInputStream(filename); 
    			byte[] data = new byte[in.available()]; 
     
    			in.read(data); 
    			in.close(); 
     
    			return data; 
     
    		} catch (FileNotFoundException x) { 
    			throw new ClassNotFoundException(name,x); 
    		} catch (IOException x) { 
    			throw new ClassNotFoundException(name,x); 
    		}
    	}
     
    }
    Voici un lien permettant de télécharger l'ensemble des librairies nécessaires à l'utilisation de poi:
    http://apache.cict.fr/poi/dev/bin/

    Voici un exemple de la classe simplifiée contenant la méthode à appeler, peut-être mon problème sera-il plus clair:


    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
    public class XlsTools {
     
    	public void removeEmptyColumn(){
     
    		try
    		{
     
    		    String file = "C:/entree.xlsx";
     
    		    Workbook wb = new XSSFWorkbook(file);
    		    Sheet sheet = wb.getSheetAt(0);
    		    Row row = sheet.getRow(0);
    		    int nbCols = row.getLastCellNum();
     
    		    for (int i = 0; i < nbCols; i++) {
     
    		    	if(row.getCell(i).toString().equals(""))
    		    		sheet.setColumnWidth(i, 0);
                       }
     
    		    String file2 = "C:/sortie.xlsx";
    		    FileOutputStream fout = new FileOutputStream(file2);
    		    wb.write(fout);
     
     
    		}
    		catch (IOException e) {
    			e.printStackTrace();
    		}
     
     
    	}
     
    }
    A l'instanciation de la classe WorkBook de poi, l'erreur affichée dans le message précédent apparait.


    Enfin, voici l'appel de la méthode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    MyClassLoader loader = new MyClassLoader(((URL[])urls.toArray(new URL[urls.size()])));
    Class classe = loader.loadClass("XlsTools");			 
     
    Method method = classe.getMethod("removeEmptyColumn", null);
    method.invoke(classe.newInstance(), null);

    Merci

  10. #10
    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
    as-tu essayé ce que je t'ai mentionné avec le context ClassLoader?

Discussions similaires

  1. Compilation "javac" avec une librairie .jar
    Par visiwi dans le forum Langage
    Réponses: 1
    Dernier message: 12/07/2008, 18h12
  2. Générer un jar avec ces librairies dépendantes
    Par untipy dans le forum NetBeans
    Réponses: 1
    Dernier message: 30/08/2007, 18h32
  3. probleme jar avec librairie externe
    Par pitbul44 dans le forum JBuilder
    Réponses: 2
    Dernier message: 07/01/2007, 12h09
  4. Créer un jar avec des librairies externes
    Par bart64 dans le forum Langage
    Réponses: 4
    Dernier message: 28/07/2006, 05h37
  5. [POI]Exportation de Jar avec librairies
    Par leminipouce dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 26/10/2005, 18h20

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