Why is it so hard to do this in Java? If you want to have any kind of module system you need to be able to load JAR files dynamically. I\'m told there\'s a way of doing it b
The solution proposed by jodonnell is good but should be a little bit enhanced. I used this post to develop my application with success.
Firstly we have to add
Thread.currentThread().setContextClassLoader(classLoader);
or you will not able to load resource (such as spring/context.xml) stored into the jar.
your jars into the parent class loader or you will not able to understand who is loading what.
see also Problem reloading a jar using URLClassLoader
However, OSGi framework remain the best way.
With Java 9, the answers with URLClassLoader
now give an error like:
java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
This is because the class loaders used have changed. Instead, to add to the system class loader, you can use the Instrumentation API through an agent.
Create an agent class:
package ClassPathAgent;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;
public class ClassPathAgent {
public static void agentmain(String args, Instrumentation instrumentation) throws IOException {
instrumentation.appendToSystemClassLoaderSearch(new JarFile(args));
}
}
Add META-INF/MANIFEST.MF and put it in a JAR file with the agent class:
Manifest-Version: 1.0
Agent-Class: ClassPathAgent.ClassPathAgent
Run the agent:
This uses the byte-buddy-agent library to add the agent to the running JVM:
import java.io.File;
import net.bytebuddy.agent.ByteBuddyAgent;
public class ClassPathUtil {
private static File AGENT_JAR = new File("/path/to/agent.jar");
public static void addJarToClassPath(File jarFile) {
ByteBuddyAgent.attach(AGENT_JAR, String.valueOf(ProcessHandle.current().pid()), jarFile.getPath());
}
}