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?
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With