I am implementing an ant task as a wrapper for another class, which loads other several classes using the system class loader. Now, the task is in the same jar of these other classes, so I wonder why it is not finding them, since the task is running
Please notice that my classes are in the $CLASSPATH
env variable. The problem will not occur if I export LOCALCLASSPATH=$CLASSPATH
Minimal example:
<taskdef name="mytask" classname="my.package.MyTask" />
<target name="compile">
<mytask />
</target>
you can easily see the problem here
public class MyTask extends Task {
public void execute() throws BuildException {
try {
ClassLoader cl = ClassLoader.getSystemClassLoader();
// this will only print the ant jar file path
for(URL url: ((URLClassLoader)cl).getURLs()){
log(url.getFile());
}
cl.loadClass("my.package.OtherClass"); // throws an exception
} catch (Exception ex) {
throw new BuildException(ex);
}
}
}
The ant
shell script reworks the classpath internally, so the SystemClassLoader contains only a minimal part of the "real" classpath
tl;dr: use
ClassLoader cl = Thread.currentThread().getContextClassLoader();
instead of
ClassLoader cl = ClassLoader.getSystemClassLoader();
From the Mailing List, Rainer Noack:
if you're launching ant via shell script, it is using oata.launcher.Launcher.java
This class reorganises the classpath a bit. The env variable CLASSPATH and the classpath commandline argument are stripped and replaced by the minimum classpath used to launch ant. A child classloader of the system classloader is created with the original CLASSPATH entries. The oata.Project is then loaded with this classloader.
The problem is that the loader in ClassLoader.getSystemClassLoader()
is actually untouched, the one that changes (i.e., the one that honors $CLASSPATH, -lib, etc.) can be retrieved using Thread.currentThread().getContextClassLoader()
.