2010-12-09 4 views
1

J'essaie d'utiliser Class.forName pour charger dynamiquement une classe à partir d'un fichier .jar sur le système de fichiers lors de l'exécution. La classe que j'essaie de charger implémente une interface dans un autre fichier .jar, donc j'utilise mon propre URLClassLoader pour référencer les deux .jars.Problème avec Java Class.forName

Le code fonctionne lorsqu'il n'est pas appelé dans le contexte de l'application web (j'ai testé cela en copiant et collant la méthode dans un programme séparé et en l'appelant depuis le principal). Cependant, lorsque j'exécute/débogue l'application web (j'utilise NetBeans) le code échoue. La méthode newInstance déclenche une exception ClassCastException lorsque j'essaie de convertir l'instance vers l'interface spécifiée dans jar_file_dependencies.jar.

Voici le code correspondant si cela aide:

 File gameJar = new File("C:\\file_path\\jar_file.jar"); 

     File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar"); 

     URLClassLoader cl = new URLClassLoader(new URL[] 
       { 
        gameJar.toURI().toURL(), 
        gameDependenciesJar.toURI().toURL() 
       }); 

     Class clazz = Class.forName("MyClass", true, cl); 

     IMyClass myClass = (IMyClass)clazz.newInstance(); 

     System.out.println(game); 

    } catch (Exception e) 
    { 
     System.out.println(e.getMessage()); 
    } 

Toutes les suggestions pour expliquer pourquoi ce code fonctionne dans un programme et non une autre serait grandement apprécié.

Un grand merci, Dan

+1

Se pourrait-il cette question: http://stackoverflow.com/questions/2081000/java-lang-classcastexception-when-casting-object-result-of-java-lang-reflect-met? – Lars

+1

@Lars, je pense que c'est effectivement le problème. Allait suggérer la même chose - donner le URLClassLoader un parent. –

Répondre

1

réponse courte sans entrer dans trop de détails poilus: l'un ou les deux gameJar et gameDependenciesJar contiennent probablement une définition de la classe IMyClass/interface. La règle de base lors de l'utilisation de classloaders enfants est que le classloader ne doit contenir aucune des classes «partagées» - celles-ci ne doivent exister que dans le chargeur de classe parent.

Explication partielle: Les chargeurs de classe d'applications Web ont généralement des stratégies de délégation différentes de celles des chargeurs de classe normaux. souvent, ils préfèrent la classe de l'enfant à celle des parents. les classloaders normaux préfèrent généralement la classe du parent à celle de l'enfant. Dans votre application Web, vous obtenez deux définitions distinctes de la classe IMyClass (une dans le classloader parent, une dans l'enfant). dans votre application normale, la définition IMyClass du classloader enfant est ignorée, donc une seule définition est chargée (dans le classloader parent), et tout est content.

+0

Merci beaucoup! Problème résolu!! –

0

Peut-être que cela vous aidera, (non testé):

ClassLoader clsLoader = Thread.currentThread().getContextClassLoader(); 
if (clsLoader == null) { 
    clsLoader = this.getClass().getClassLoader(); 
} 

URLClassLoader cl = new URLClassLoader(new URL[] 
       { 
        gameJar.toURI().toURL(), 
        gameDependenciesJar.toURI().toURL() 
       }, clsLoader); 

En outre, vous devriez passer un complet nom déclarative de la classe MyClass au lieu de simplement l'appeler MyClass dans Class.forName().

E.g.

Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);