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 newClassLoader
.
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
Which Cipher Suites to Enable for Ssl Socket
How to Add Jradiobutton to Group in Jtable
Certain Unix Commands Fail with "... Not Found", When Executed Through Java Using Jsch
Java: Notify() VS. Notifyall() All Over Again
Add Jar Files to a Spark Job - Spark-Submit
What Is the "Owning Side" in an Orm Mapping
Java Time-Based Map/Cache with Expiring Keys
Arithmeticexception: "Non-Terminating Decimal Expansion; No Exact Representable Decimal Result"
Java: How to Split an Arraylist in Multiple Small Arraylists
Handling Passwords Used for Auth in Source Code
How to Change Jdk Version for an Eclipse Project