Adding Files to Java Classpath at Runtime

Can a directory be added to the class path at runtime?

You can use the following method:

URLClassLoader.addURL(URL url)

But you'll need to do this with reflection since the method is protected:

public static void addPath(String s) throws Exception {
File f = new File(s);
URL u = f.toURL();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u});
}

See the Java Trail on Reflection. Especially the section Drawbacks of Reflection

How to add an external jar file to the classpath dynamically at runtime?

URLClassLoader child = new URLClassLoader (myJar.toURL(), this.getClass().getClassLoader());
Class classToLoad = Class.forName ("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod ("myMethod");
Object instance = classToLoad.newInstance ();
Object result = method.invoke (instance);

Source: https://stackoverflow.com/a/60775/1360074

Java add Classpaths at runtime

Problem is, the classes must be found my the system ClassLoader not by a new ClassLoader.

It sound like your current solution of relaunching the JVM is the only clean way to do it.

The system ClassLoader cannot be changed, and you cannot add extra JARs to it at runtime.

(If you tried to use reflection to mess with the system classloader's data structures, at best it will be non-portable and version dependent. At worst it will be either error prone ... or blocked by the JVM's runtime security mechanisms.)

The solution suggested by Johannes Kuhn in a comment won't work. The java.system.class.loader property is consulted during JVM bootstrap. By the time your application is running, making changes to it will have no effect. I am not convinced that the approach in his Answer would work either.


Here is one possible alternative way to handle this ... if you can work out what the missing JARs are early enough.

Write yourself a Launcher class that does the following:

  • Save the command line arguments
  • Find the application JAR file
  • Extract the Main-Class and Class-Path attributes from the MANIFEST.MF.
  • Work out what the real classpath should be based on the above ... and other application specific logic.
  • Create a new URLClassLoader with the correct classpath, and the system classloader as its parent.
  • Use it to load the main class.
  • Use reflection to find the main classes main method.
  • Call it passing the save command line arguments.

This is essentially the approach that Spring Bootstrap and OneJar (and other things) take to handle the "jars in a jar" problem and so on. It avoids launching 2 VMs.

How to load JAR files dynamically at Runtime?

The reason it's hard is security. Classloaders are meant to be immutable; you shouldn't be able to willy-nilly add classes to it at runtime. I'm actually very surprised that works with the system classloader. Here's how you do it making your own child classloader:

URLClassLoader child = new URLClassLoader(
new URL[] {myJar.toURI().toURL()},
this.getClass().getClassLoader()
);
Class classToLoad = Class.forName("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod("myMethod");
Object instance = classToLoad.newInstance();
Object result = method.invoke(instance);

Painful, but there it is.



Related Topics



Leave a reply



Submit