How to get classpath from classloader?
If the classloader uses URLs, it must be a URLClassloader
. What you have access to is the URLs which defines the classpath for it along side with its parent ClassLoader
.
To get the URLs, simply do the following:
((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
In case other answers don't work, try this:
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
System.out.println(url.getFile());
}
The cleanest way to enumerate the classpath today is to use the ClassGraph library (I am the author). Note that the old answer of reading the java.class.path
property or calling ((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
is woefully inadequate if you want your code to be portable today, because numerous runtime environments no longer use java.class.path
, and/or their classloaders don't extend URLClassLoader
, and/or they use some obscure mechanism for extending the classpath (like the Class-Path:
property in a jar's manifest file), and/or your code may be run as a module in JDK 9+ (or your code will be run on the traditional classpath in JDK9+, but the standard JDK classloaders for the traditional classpath don't even extend URLClassLoader
anymore).
ClassGraph handles an enormous number of classpath specification mechanisms and classloader implementations automatically. For most of the supported classloaders, custom reflection code has been written for ClassGraph to obtain the classpath from the classloader (this is required since the ClassLoader
API does not have any standard mechanism for obtaining the classpath). You could write your own code for this, but probably it will only support URLClassLoader
without expending significant effort -- so it is probably better to just use ClassGraph, since the work is already done for you.
To get the classpath (and non-system modular jars added to the module path), just call:
List<URI> classpath = new ClassGraph().getClasspathURIs();
Note that in Java 9+, modules (or jlink'd jars) may appear in the list with jrt:
URIs, which you can't do much with directly (other than use ClassGraph to read resources and classes from them, since ClassGraph can additionally use the JPMS API to access these resources and classes). You can also use ClassGraph to enumerate or scan all classes and/or all resources in the classpath (see the ClassGraph wiki).
In a modular project in Java 9+, you may also want to obtain a list of ModuleReference
objects for visible modules in the system. These can be obtained by calling the following (ModuleRef
is a wrapper for ModuleReference
that is backwards compatible, so you can compile your code on JDK 7/8 but still take advantage of module features on JDK 9+):
List<ModuleRef> modules =
new ClassGraph()
.enableSystemPackages() // Optional, to return system modules
.getModules();
Or you can get the actual module path passed into the commandline (--module-path
, --patch-module
, --add-exports
etc.) by calling the following, returning a list of ModulePathInfo
objects:
List<ModulePathInfo> modulePathInfo = new ClassGraph().getModulePathInfo();
For future reference, in case you need to pass in the class path to ProcessBuilder
:
StringBuffer buffer = new StringBuffer();
for (URL url :
((URLClassLoader) (Thread.currentThread()
.getContextClassLoader())).getURLs()) {
buffer.append(new File(url.getPath()));
buffer.append(System.getProperty("path.separator"));
}
String classpath = buffer.toString();
int toIndex = classpath
.lastIndexOf(System.getProperty("path.separator"));
classpath = classpath.substring(0, toIndex);
ProcessBuilder builder = new ProcessBuilder("java",
"-classpath", classpath, "com.a.b.c.TestProgram");