The following code adds jar file to the build path, it works fine with Java 8. However, it throws exception with Java 9, the exception is related to the cast to URLClassLoader. Any ideas how this can be solved? an optimal solution will edit it to work with both Java 8 & 9.
private static int AddtoBuildPath(File f) {
try {
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader, u.toURL());
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
return 1;
}
return 0;
}
I have stumbled over this issue a while ago. As many, I had used a method similar to that in the question
to dynamically add paths to the classpath at runtime. The code in the question is probably bad style in multiple aspects: 1) assuming that
ClassLoader.getSystemClassLoader()
returns anURLClassLoader
is an undocumented implementation detail and 2) using reflection to makeaddURL
public is maybe another one.Cleaner way to dynamically add classpaths
In case that you need to use the additional classpath URLs for class loading through „
Class.forName
“, a clean, elegant and compatible (Java 8 to 10) solution is the following:1) Write your own class loader by extending URL classloader, having a public
addURL
method2) Declare a (singleton/app wide) object of your classloader
and instanciate it via
Note: The system class loader is the parent. Classes loaded though
classLoader
know those who can be loaded throughthis.getClass().getClassLoader()
but not the other way around.3) Add additional classpaths whenever needed (dynamically):
4) Instanciate objects or your app though your singleton classloader via
Note: Since class loaders try a delegation to the parent class loader prior loading a class (and the parent to its parent), you have to make sure that the class to load is not visible to the parent class loader to make sure that it is loaded through the given class loader. To make this clearer: if you have
ClassPathB
on your system class path and later addClassPathB
and someClassPathA
to your customclassLoader
, then classes underClassPathB
will be loaded through the system classloader and classes underClassPathA
are not known to them. However, if you removeClassPathB
from you system class path, such classes will be loaded through your customclassLoader
, and then classes under ClassPathA are known to those under ClassPathB.5) You may consider passing your class loader to a thread via
in case that thread uses
getContextClassLoader
.I was given a spring boot application that runs in Java 8. I had the task to upgrade it to Java 11 version.
Issue faced:
Caused by: java.lang.ClassCastException: jdk.internal.loader.ClassLoaders$AppClassLoader (in module: java.base) cannot be cast to java.net.URLClassLoader (in module: java.base)
Way around used:
Create a class:
Create Another class:
Now set it in the current thread from your main class (Right at the beginning of your application)
Hope this solution works for your!!!
i found this, and worked for me.
String pathSeparator = Syste .getProperty("path.separator"); String[] classPathEntries = System.getProperty("java.class.path") .split(pathSeparator);
from the web site https://blog.codefx.org/java/java-11-migration-guide/#Casting-To-URL-Class-Loader
If you're just looking to read the current classpath, for example because you want to spin up another JVM with the same classpath as the current one, you can do the following:
By default the final fields in the $AppClassLoader class cannot be accesed via reflection, an extra flag needs to be passed to the JVM:
You've run into the fact that the system class loader is no longer a
URLClassLoader
. As indicated byClassLoader::getSystemClassLoader
's return type, this was an implementation detail, albeit one that a non-negligible amount of code relied upon.Judging by the comments, you are looking for a way to dynamically load classes at run time. As Alan Bateman points out, this can not be done in Java 9 by appending to the class path.
You should instead consider creating a new class loader for that. This has the added advantage that you'll be able to get rid of the new classes as they are not loaded into the application class loader. If you're compiling against Java 9, you should read up on layers - they give you a clean abstraction for loading an entirely new module graph.
Shadov pointed to a thread at the oracle community. There is the correct answer:
The caveats mentioned there are also important: