I have taken a look here before to see how I could load the jar into the classpath dynamically. At the time, this solution proposed worked flawlessly:
File file = ...
URL url = file.toURI().toURL();
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, URL);
However, this wasn't possible in Java 9+, but there was a hack involving Module#addOpens which allowed the URL method to be open. For example, the code to open the module would look like this:
try {
final Class<?> moduleClass = Class.forName("java.lang.Module");
final Method getModuleMethod = Class.class.getMethod("getModule");
final Method addOpensMethod = moduleClass.getMethod("addOpens", String.class, moduleClass);
final Object urlClassLoaderModule = getModuleMethod.invoke(URLClassLoader.class);
final Object thisModule = getModuleMethod.invoke(DependencyUtilities.class);
addOpensMethod.invoke(
urlClassLoaderModule, URLClassLoader.class.getPackage().getName(), thisModule);
Logger.info(
"User is using Java 9+, meaning Reflection Module does have to be opened. You may safely ignore this error.");
} catch (final ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InvocationTargetException ignored) {
Logger.info(
"User is using Java 8, meaning Reflection Module does NOT have to be opened. You may safely ignore this error.");
// Java 8 doesn't have module class -- you can ignore the error.
}
Unfortunately, Java 16 has led to changes that strictly enforce encapsulation. One of these changes included blocking illegal reflection involving the URLClassLoader#addURL method. This means that for Java 16 and above, we aren't allowed to use this trick to load the jars dynamically into the runtime.
You may ask why I am not allowed to shade the dependencies into my application. The reason due to being that restrictions force my application to fit within a certain size (2 MB). Most famously used libraries in Java will surpass this limit, especially the ones that I am using. (The jar itself must be under a certain size, but it can download dependencies to a separate folder and load them)
Another restriction includes loading it during runtime. My application isn't necessarily standalone, meaning that I lack the ability to run it with JVM Arguments. That means that I would be unable to use this as a solution.
Does anyone have some suggestions I could take?