I have an ANT script that calls a Java 11 class using a custom classpath
<path id="ant.classpath">
<fileset dir="${basedir}/lib/ant">
<include name="*.jar" />
</fileset>
</path>
<taskdef name="myTaskDef" classname="A.SomeClass" classpathref="ant.classpath" />
The ${basedir}/lib/ant directory contains several jars
These jars all load into the classpath ${ant.classpath} just fine.
The workflow is like this: A.jar calls B.jar, and B.jar calls C.jar.
So, A.jar calls classes in B.jar no problem. It uses the import statement in JAVA to call the classes:
import B.SomeClass;
This works perfectly.
However, B.jar calls C.jar and it fails.
I was able to inspect the source code code for both third-party libraries and have learned that B.jar calls classes from C.jar using Java's Classloader class. It doesn't use the import statement.
Below is code from a class inside B.jar
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
....
classLoader.loadClass("C.SomeClass");
The exception that I get is:
java.lang.ClassNotFoundException: C.SomeClass
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at B.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
I was able to verify that C.SomeClass does exist in C.jar.
I suspect that it's loading a different classpath than the one provided by the ant taskdef. When I try to load the C.jar class from within my library (A.jar) using the ClassLoader, I get the same exception. But import works just fine.
I'm sort of at a loss at what to do because I can't get B.jar to properly load C.jar through Ant.
EDIT:
In case it's useful, I'm using Java 11, and B.jar is really jaxb-api-2.4.0.jar (javax.xml.bind) and C.jar is jaxb-runtime-2.4.0.jar (com.sun.xml.bind) plus its dependencies (jaxb-core, stax-ex, txw2, etc). I get the ClassNotFoundException, when I call:
JAXBContext jc = JAXBContext.newInstance(Feature.class);
And it can't find the class com.sun.xml.bind.v2.ContextFactory, which I've confirmed does indeed exist.
So, I messed around in A.jar and learned that getClass().getClassLoader() and Thread.currentThread().getContextClassLoader() return different things. The getClass().getClassLoader() contains the ANT classpath that I set in the ANT script, the the Thread classloader does not.
I can't change the code in B.jar since it's a 3rd-party library, however, I was able to set the Thread's classloader in my code using the following:
ClassLoader cl = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
I put this in the code right before my code calls B.jar, and subsequently C.jar. It worked perfectly!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.