How to get classpath from classloader?

JavaClassloaderContextclassloader

Java Problem Overview


I am using some third party code which when given a '-classpath' command line argument doesnt set the java.class.path, but instead just creates a classloader, adds all the urls for the items on the command line specified classpath to the classloader, and then sets it to be the context classloader. In a plugin class to this code that I have written, I get an instance of this classloader, and somehow need to use it to get back the underlying classpath, so that I can use it in an invocation of JavaCompiler.getTask(...) and compile some other code on the fly. However there doesn't seem to be anyway to get the ClassPath from the ClassLoader, and as java.class.path is unset, I can't seem to access the underlying classpath that the application was initially invoked with...Any ideas?

Java Solutions


Solution 1 - Java

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()

Solution 2 - Java

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();

Solution 3 - Java

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");

Solution 4 - Java

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());
}

Solution 5 - Java

Drop this code into an empty jsp page to view classLoader hierarchy and associated jars loaded at each level.

visit() method below could also be used on its own

<%!
	public void visit(StringBuilder sb, int indent, ClassLoader classLoader) {
		if (indent > 20 || classLoader == null)
			return;
		String indentStr = new String(new char[indent]).replace("\0", "    ");
		sb.append("\n");
		sb.append(indentStr);
		sb.append(classLoader.getClass().getName());
		sb.append(":");
		if (classLoader instanceof java.net.URLClassLoader) {
			java.net.URL[] urls = ((java.net.URLClassLoader)classLoader).getURLs();
			for (java.net.URL url : urls) {
				sb.append("\n");
				sb.append(indentStr);
				sb.append(url);
			}
		}
		sb.append("\n");
		visit(sb, indent + 1, classLoader.getParent());
	}

%>

<%
StringBuilder sb = new StringBuilder();
visit(sb,1,this.getClass().getClassLoader());
%>
<pre>
<%=sb%>
</pre>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarcus MathioudakisView Question on Stackoverflow
Solution 1 - JavaAdel BoutrosView Answer on Stackoverflow
Solution 2 - JavaLuke HutchisonView Answer on Stackoverflow
Solution 3 - JavaBJ Dela CruzView Answer on Stackoverflow
Solution 4 - JavaYavin5View Answer on Stackoverflow
Solution 5 - JavaPrashant BhateView Answer on Stackoverflow