运行 Ant taskdef 时的多个类路径?
Multiple classpaths when running Ant taskdef?
我有一个使用自定义 classpath
调用 Java 11 class 的 ANT 脚本
<path id="ant.classpath">
<fileset dir="${basedir}/lib/ant">
<include name="*.jar" />
</fileset>
</path>
<taskdef name="myTaskDef" classname="A.SomeClass" classpathref="ant.classpath" />
${basedir}/lib/ant 目录包含几个 jar
- A.jar - 我的图书馆
- B.jar - 第三方库
- C.jar - 第三方库,与 B.Jar
不同的公司
这些 jar 都可以加载到 class路径 ${ant.classpath} 中。
工作流程是这样的:
A.jar 调用 B.jar,B.jar 调用 C.jar。
因此,A.jar 在 B.jar 中调用 class 没问题。它使用 JAVA 中的 import 语句调用 classes:
import B.SomeClass;
这非常有效。
但是,B.jar 调用了 C.jar,但失败了。
我能够检查这两个第三方库的源代码,并且了解到 B.jar 使用 Java 从 C.jar 调用 classes类加载器 class。它不使用导入语句。
下面是来自 class inside B.jar
的代码
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
....
classLoader.loadClass("C.SomeClass");
我得到的异常是:
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)
我能够验证 C.SomeClass 确实存在于 C.jar。
我怀疑它加载的 class 路径与 ant taskdef 提供的路径不同。当我尝试使用 ClassLoader 从我的库 (A.jar) 中加载 C.jar class 时,我遇到了同样的异常。但是导入工作正常。
我有点不知所措,因为我无法 B.jar 通过 Ant 正确加载 C.jar。
编辑:
万一有用,我用的是Java11,B.jar真的是jaxb-api-2.4.0.jar (javax.xml.bind ) 并且 C.jar 是 jaxb-runtime-2.4.0.jar (com.sun.xml.bind) 加上它的依赖项(jaxb-core、stax-ex、txw2 等)。当我调用时,我得到了 ClassNotFoundException:
JAXBContext jc = JAXBContext.newInstance(Feature.class);
而且找不到 class com.sun.xml.bind.v2.ContextFactory,我已经确认它确实存在。
所以,我在 A.jar 中乱搞,了解到 getClass().getClassLoader() 和 Thread.currentThread().getContextClassLoader() return 不同的东西。 getClass().getClassLoader() 包含我在 ANT 脚本中设置的 ANT 类路径,Thread 类加载器没有。
我无法更改 B.jar 中的代码,因为它是第 3 方库,但是,我可以使用以下代码在我的代码中设置 Thread 的类加载器:
ClassLoader cl = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
我在我的代码调用 B.jar 之前将其放入代码中,随后 C.jar。效果很好!
我有一个使用自定义 classpath
调用 Java 11 class 的 ANT 脚本<path id="ant.classpath">
<fileset dir="${basedir}/lib/ant">
<include name="*.jar" />
</fileset>
</path>
<taskdef name="myTaskDef" classname="A.SomeClass" classpathref="ant.classpath" />
${basedir}/lib/ant 目录包含几个 jar
- A.jar - 我的图书馆
- B.jar - 第三方库
- C.jar - 第三方库,与 B.Jar 不同的公司
这些 jar 都可以加载到 class路径 ${ant.classpath} 中。
工作流程是这样的: A.jar 调用 B.jar,B.jar 调用 C.jar。
因此,A.jar 在 B.jar 中调用 class 没问题。它使用 JAVA 中的 import 语句调用 classes:
import B.SomeClass;
这非常有效。
但是,B.jar 调用了 C.jar,但失败了。
我能够检查这两个第三方库的源代码,并且了解到 B.jar 使用 Java 从 C.jar 调用 classes类加载器 class。它不使用导入语句。
下面是来自 class inside B.jar
的代码ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
....
classLoader.loadClass("C.SomeClass");
我得到的异常是:
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)
我能够验证 C.SomeClass 确实存在于 C.jar。
我怀疑它加载的 class 路径与 ant taskdef 提供的路径不同。当我尝试使用 ClassLoader 从我的库 (A.jar) 中加载 C.jar class 时,我遇到了同样的异常。但是导入工作正常。
我有点不知所措,因为我无法 B.jar 通过 Ant 正确加载 C.jar。
编辑:
万一有用,我用的是Java11,B.jar真的是jaxb-api-2.4.0.jar (javax.xml.bind ) 并且 C.jar 是 jaxb-runtime-2.4.0.jar (com.sun.xml.bind) 加上它的依赖项(jaxb-core、stax-ex、txw2 等)。当我调用时,我得到了 ClassNotFoundException:
JAXBContext jc = JAXBContext.newInstance(Feature.class);
而且找不到 class com.sun.xml.bind.v2.ContextFactory,我已经确认它确实存在。
所以,我在 A.jar 中乱搞,了解到 getClass().getClassLoader() 和 Thread.currentThread().getContextClassLoader() return 不同的东西。 getClass().getClassLoader() 包含我在 ANT 脚本中设置的 ANT 类路径,Thread 类加载器没有。
我无法更改 B.jar 中的代码,因为它是第 3 方库,但是,我可以使用以下代码在我的代码中设置 Thread 的类加载器:
ClassLoader cl = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
我在我的代码调用 B.jar 之前将其放入代码中,随后 C.jar。效果很好!