Dynamic loading of class from external jar and NoClassDefFoundError
Dynamic loading of class from external jar and NoClassDefFoundError
I don't know if this is the correct thread to post in my question.
What is the situation?
I've a web application, we call it WA, that uses JSF. WA run on Glassfish 3.
This application has some panel (extended from primefaces.Panel) and i want to bind the panel to some object P:
<p:panel ... binding="{bean.panel}" />
<p:panel ... binding="{bean.panel}" />
The panel must be loaded dynamically from an external jar.
The P class is something like
public class ModTest {
public BssPanel pannello;
public ModTest() {
this.pannello = new BssPanel();
BssOutputText testo = new BssOutputText();
testo.setValue("modulo vuoto, di test");
this.pannello.setHeader("Modulo di Test");
this.pannello.getChildren().add(testo);
}
//setter and getter
}
public class ModTest {
public BssPanel pannello;
public ModTest() {
this.pannello = new BssPanel();
BssOutputText testo = new BssOutputText();
testo.setValue("modulo vuoto, di test");
this.pannello.setHeader("Modulo di Test");
this.pannello.getChildren().add(testo);
}
//setter and getter
}
The ModTest class is in another jar file, called ModTest.jar. I want to load the class at runtime from the external jar so i can change the "panel" without recompile WA.
So, I built a bean B that read from database the path of jar file and the classname.
B then must instantiate an object A of tipe P and return A.pannello to show it on screen.
The loader function is:
public static Object caricaClasse(String jar, String nomeClasse){
File jarFile = new File(jar);
Object instance = null;
try {
URL jarpath = jarFile.toURI().toURL();
String jarUrl = "jar:"+jarpath+"!/";
URL urls[] = {new URL(jarUrl)};
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (MalformedURLException ex) {
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
} catch(ClassNotFoundException ex){
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
} catch(IllegalAccessException | InstantiationException ex){
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
}
return instance;
}
public static Object caricaClasse(String jar, String nomeClasse){
File jarFile = new File(jar);
Object instance = null;
try {
URL jarpath = jarFile.toURI().toURL();
String jarUrl = "jar:"+jarpath+"!/";
URL urls[] = {new URL(jarUrl)};
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (MalformedURLException ex) {
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
} catch(ClassNotFoundException ex){
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
} catch(IllegalAccessException | InstantiationException ex){
Logger.getLogger(BssLoader.class.getName()).log(Level.SEVERE, null, ex);
}
return instance;
}
What is the problem?
It works untill instance = classToLoad.newInstance(); at this time throw java.lang.NoClassDefFoundError: com/bss/primefaces/panel/BssPanel.
com/bss/primefaces/panel/BssPanel is missing or it is not found. That class is in another library, component.jar.
The ModTest.jar hasn't component.jar inside but WA.war has it.
What are the questions?
- ModTest.jar is a maven project so, how i can force to put all dependency jar in ModTest.jar? It solve the problem? I need to create a normal java project?
otherwise
- There is a way to provide the necessary jar without modifing ModTest.jar, like read it from glassfish's lib directory? How I must provide all the dependencies in the correct way?