Is there a way to remove a folder from the classpath similar to adding a folder at runtime (Can a directory be added to the class path at runtime?)
-
1Have you tried anything? Part of being a good developer is having the desire to experiment and figure stuff out for yourself. There's nothing wrong with asking, but this would be a much better question if you were to start out with "Here's what I.ve tried so far but it hasn't worked"... – Jim Garrison Jan 07 '16 at 18:24
-
2I'd like to know if there is any real life scenario for this requirement. – Mrinal Jan 07 '16 at 18:25
-
1I haven't tried anything myself, more just digging around for possible solutions. As for real life scenarios.. I can't give you a production scenario, as this would only be used within our test environments. – jpints14 Jan 18 '16 at 17:56
-
1@mks The only one I can think of is in a unit test, where you are testing handling of error conditions - specifically a file not found. – Stewart Apr 07 '17 at 16:26
5 Answers
Please find below a snippet as technical example to demonstrate adding / removing a path.
create following source files in any directory
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Stack;
import sun.misc.URLClassPath;
public class EvilPathDemo {
public static void addPath(String path) throws Exception {
URL u = new File(path).toURI().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});
}
public static void removePath(String path) throws Exception {
URL url = new File(path).toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader)
ClassLoader.getSystemClassLoader();
Class<?> urlClass = URLClassLoader.class;
Field ucpField = urlClass.getDeclaredField("ucp");
ucpField.setAccessible(true);
URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader);
Class<?> ucpClass = URLClassPath.class;
Field urlsField = ucpClass.getDeclaredField("urls");
urlsField.setAccessible(true);
Stack urls = (Stack) urlsField.get(ucp);
urls.remove(url);
}
public static void main(String[] args) throws Exception {
String parm = args.length == 1 ? args[0] : "";
String evilPath = "/tmp";
String classpath = System.getProperty("java.class.path");
boolean isEvilPathSet = false;
for (String path : classpath.split(File.pathSeparator)) {
if (path.equalsIgnoreCase(evilPath)) {
System.out.printf("evil path '%s' in classpath%n", evilPath);
isEvilPathSet = true;
break;
}
}
if (isEvilPathSet && parm.equalsIgnoreCase("REMOVE")) {
System.out.printf("evil path '%s' will be removed%n", evilPath);
removePath(evilPath);
}
tryToLoad("Foo");
if (parm.equalsIgnoreCase("ADD")) {
System.out.printf("evil path '%s' will be added%n", evilPath);
addPath(evilPath);
}
tryToLoad("Bar");
}
private static void tryToLoad(String className) {
try {
Class<?> foo = Class.forName(className);
System.out.printf("class loaded: %s%n", foo.getName());
} catch (ClassNotFoundException ex) {
System.out.println(ex);
}
}
}
.
public class Foo {
static {
System.out.println("I'm foo...");
}
}
.
public class Bar {
static {
System.out.println("I'm bar...");
}
}
compile them as follow
javac EvilPathDemo.java
javac -d /tmp Foo.java Bar.java
During the test we will try to load the classes Foo
and Bar
.
without /tmp in the classpath
java -cp . EvilPathDemo
java.lang.ClassNotFoundException: Foo
java.lang.ClassNotFoundException: Bar
adding /tmp to the classpath
java -cp . EvilPathDemo add
java.lang.ClassNotFoundException: Foo
evil path '/tmp' will be added
I'm bar...
class loaded: Bar
with /tmp in the classpath
java -cp .:/tmp EvilPathDemo
evil path '/tmp' in the classpath
I'm foo...
class loaded: Foo
I'm bar...
class loaded: Bar
remove /tmp from the classpath
java -cp .:/tmp EvilPathDemo remove
evil path '/tmp' in the classpath
evil path '/tmp' will be removed
java.lang.ClassNotFoundException: Foo
java.lang.ClassNotFoundException: Bar
During the testing I found out that following cases are not working.
- addPath(evilPath);
tryToLoad("Foo");
removePath(evilPath); // had not effect
tryToLoad("Bar"); - removePath(evilPath);
tryToLoad("Foo");
addPath(evilPath); // had no effect
tryToLoad("Bar"); - tryToLoad("Foo");
removePath(evilPath); // had no effect
tryToLoad("Bar");
I did not spent time to find out why. Because I don't see any practical use in it. If you really need/wish to play with the classpaths have a look how classloaders are working.

- 22,518
- 3
- 53
- 69
The removePath
method from above did not work for me and my Weld Container, the url stack was always emtpy.
The following ugly smugly method worked:
public static void removeLastClasspathEntry() throws Exception {
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<?> urlClass = URLClassLoader.class;
Field ucpField = urlClass.getDeclaredField("ucp");
ucpField.setAccessible(true);
URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader);
Field loadersField = URLClassPath.class.getDeclaredField("loaders");
loadersField.setAccessible(true);
List jarEntries = (List) loadersField.get(ucp);
jarEntries.remove(jarEntries.size() - 1);
Field pathField = URLClassPath.class.getDeclaredField("path");
pathField.setAccessible(true);
List pathList = (List) pathField.get(ucp);
URL jarUrl = (URL) pathList.get(pathList.size() - 1);
String jarName = jarUrl.toString();
pathList.remove(pathList.size() - 1);
Field lmapField = URLClassPath.class.getDeclaredField("lmap");
lmapField.setAccessible(true);
Map lmapMap = (Map) lmapField.get(ucp);
lmapMap.remove(jarName.replaceFirst("file:/", "file:///"));
}

- 295
- 3
- 9
-
I think that only works if the JAR you want to remove happens to be the last one in the list. However with a bit of additional introspection I think the approach could be made to work – Stormcloud Jul 01 '19 at 13:46
Class loaders can be nested so instead of modifying the system class loader which is the root of the tree of class loaders, it is better to simply create a nested classloader and use that to load classes.
The system classloader itself is immutable (for good reasons) but you can do whatever you want in nested class loaders, including destroying them to unload classes and resources. This is commonly used in e.g. osgi and application servers to load/unload e.g. plugins, applications, etc.
For nested class loaders you can completely customize how to load classes. The URLClassloader
is probably a good starting point for what you want.

- 7,927
- 4
- 38
- 46
I dont think there is a straight forward way to do it. You can follow :
Get class path variables using :
System.getenv("CLASSPATH")
. It will return semi colon separated values.String classPath = System.getenv("CLASSPATH")
Take the folder path as input and replace it with "" like :
String remainigPath = classPath.replace(inputpath,"");
Put the remaining paths in an array using split method.
String[] paths = remainigPath .split(";");
For adding classPath, You already have the code.

- 3,755
- 3
- 26
- 43
I had the same issue, so I tackled it by creating a library that works on every ClassLoader
that uses a URLClassPath
(so, currently, URLClassLoader
).
The library has methods for:
- Adding new entries in front
- Appending new entries
- Remove existing entries
Please note that, since this library accesses internal and proprietary APIs, it is no guaranteed to work in future versions of the JDK. It currently does for Java 7 and Java 8 (Oracle and OpenJDK).
Here is the GitHub page (contribution is appreciated), and here is the Maven Central artifact

- 966
- 8
- 19
-
Just a note: the code is inspired by the snippets found here by [JohannSchwarz](http://stackoverflow.com/users/1979735/johannschwarz) and [SubOptimal](http://stackoverflow.com/users/2333222/suboptimal), with a few changes that should (marginally, actually) improve reliability. – Danilo Pianini Dec 07 '16 at 09:39