Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java's classloader versus jars-within-jars

We have an executable JAR file that sometimes contains other JAR files. (The whole thing rests on four other downloaded JARs, riding on the back of a giant deployed turtle in space.) At runtime, we dynamically load that nested JAR file doing the following:

// wearyingly verbose error handling elided

URL nestedURL = the_main_system_classloader.getResource("path/to/nested.jar");
File temp = File.createTempFile (....);
// copy out nestedURL contents into temp, byte for byte

URL tempURL = temp.toURI().toURL();
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{ tempURL });
Class<?> clazz = loader.loadClass("com.example.foo.bar.baz.Thing");
Thing thing = (Thing) clazz.newInstance();
// do stuff with thing

This kind of technique has been brought up here before; links include this one and this one. The code we currently have in place works...

...mostly. I'd really like to find some way of avoiding the temporary file creation and copying (and eventual cleanup, because as we all know, deleteOnExit is evil). The URL obtained right at the start points to a JAR, after all:

URL nestedURL = the_main_system_classloader.getResource("path/to/nested.jar");
// nestedURL.toString() at this point is
// "jar:file:/C:/full/path/to/the/executable.jar!/path/to/nested.jar"
URLClassLoader loader = URLClassLoader.newInstance(new URL[]{ nestedURL });
Class<?> clazz = loader.loadClass("com.example.foo.bar.baz.Thing");

But loadClass throws a ClassNotFound.

Can the URLClassLoader simply not handle this JAR-within-a-JAR case? Or do I need to do something to one or more of the paths involved (either the nestedURL or the string passed to loadClass) to make this work?

like image 538
Ti Strga Avatar asked Sep 25 '13 21:09

Ti Strga


1 Answers

AFAIK the vanilla URLClassloader cannot handle it.

So far this is your answer.

Apart from your solution there are two other possibilities that I am aware of:

  1. Create a fat jar (p.ex. using Maven Shade)
  2. Create a custom classloader, but this is kind of hard work.
like image 138
Chrstian Beutenmueller Avatar answered Oct 06 '22 22:10

Chrstian Beutenmueller