2

I have written an application which manages several plugins which are provided as jars. I load the plugin classes using an URLClassLoader which works as supposed.

But now I am writing a plugin which loads some resources which are stored inside the jar. If I start this plugin as a standalone application everything works, but if I start it from inside my application I get a NullPointerException when I try to open the resources InputStream.

I open the stream like this:

this.getClass().getResourceAsStream("/templates/template.html"); 

My Eclipse project structure looks like:

src | + My source files resources | + templates | + template.html 

The following loads my plugins:

private List<Class<?>> loadClasses(final File[] jars) { List<Class<?>> classes = new ArrayList<Class<?>>(); URL[] urls = getJarURLs(jars); URLClassLoader loader = new URLClassLoader(urls); for (File jar : jars) { JarFile jarFile = null; try { jarFile = new JarFile(jar); } catch (IOException e) { // Skip this jar if it can not be opened continue; } Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (isClassFile(entry.getName())) { String className = entry.getName().replace("/", ".").replace(".class", ""); Class<?> cls = null; try { cls = loader.loadClass(className); } catch (ClassNotFoundException e) { // Skip this jar if a class inside it can not be loaded continue; } classes.add(cls); } } try { jarFile.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { loader.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return classes; } /** * Checks if a path points to a class file or not. * * @param path the filename to check * @return {@code true} if the path points to a class file or {@code false} * if not */ private boolean isClassFile(final String path) { return path.toLowerCase().endsWith(".class") && !path.toLowerCase().contains("package-info"); } 

Then I make instances from this classes using newInstance().

I think that the root path of the plugins jar is not the same as the root path of the application or that not all contents of the jar files are loaded or both...

Can someone help me?

1
  • this.getClass().getResource("/templates/template.html); works for me fine when trying to access something in a jar. Commented Apr 16, 2014 at 13:56

1 Answer 1

1

First note, that using getClass().getResource(...) also delegates to a ClassLoader, which is also responsible for loading resources. Which class loader is used? It is the same class loader, with which the class was loaded. Point.

In your code, you build up an URLClassLoader for loading some classes. So the same URLClassLoader will then be used for loading the resources, if the above mentioned call comes from a class inside your plugin.

This all seems to be ok ... but you did a little mistake. At the end of loading you also closed the loader. This will prevent subsequent calls to loadClass or getResource from returning anything meaningful. In fact, it could null, as now the loader cannot load the resource anymore.

Conclusion: Do not close the URLClassLoader, if you still need it ofr loading purposes. Instead keep the reference to this class loader and close it at the end of your program runtime.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer! This sounds logical. I finished work for today but I will check this tommorow.
Okay, this is the solution, thank you! I have another question about this: Assuming I have two plugins which both have this /template/template.html resource in its jar. How could the ClassLoader determine which resource he would have to serve? Is he smart enough to detect that the classes come from different jars? Or do I have to create a new ClassLoader for each jar?
If the classes requesting the resources are from different JARs and these different JARs were loaded by different class loaders, then they will automagically load the correct resource.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.