简体   繁体   中英

Multiple classpaths when running Ant taskdef?

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

  • A.jar - My library
  • B.jar - Third-party library
  • C.jar - Third-party library, different company than B.Jar

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM