【问题标题】:NoClassDefFoundError: org/w3c/dom/ls/DocumentLS - issue occurring only on deployment after having fixed it on compile timeNoClassDefFoundError:org/w3c/dom/ls/DocumentLS - 在编译时修复后仅在部署时发生的问题
【发布时间】:2020-09-12 07:40:56
【问题描述】:

背景

我有一个项目,我在其中解析一些 XML 文档,我碰巧需要 xerces 依赖项:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xerces</artifactId>
    <version>2.4.0</version>
</dependency>

在使用 junit4 编写单元测试时,我每次运行单元测试时都会遇到问题,以下是我每次使用 mvn clean install 编译时都会出现的问题:

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.346 s <<< FAILURE! - in ConversionTest
[ERROR] ConversionTest.initializationError  Time elapsed: 0.054 s  <<< ERROR!
java.lang.NoClassDefFoundError: org/w3c/dom/ls/DocumentLS
        at ConversionTest.fromDirectory(ConversionTest.java:92)
        at ConversionTest.data(ConversionTest.java:65)
Caused by: java.lang.ClassNotFoundException: org.w3c.dom.ls.DocumentLS
        at ConversionTest.fromDirectory(ConversionTest.java:92)
        at ConversionTest.data(ConversionTest.java:65)

编译时解决方案

在网上搜索,我意识到我需要向我的pom.xml 添加一个新的依赖项:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

完成此操作后,测试编译良好,我可以生成我的.jar,它与以下构建插件打包在一起:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.company.tools.Application</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin> 

...并使用以下设置编译:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
                <encoding>cp1252</encoding>
                <release>11</release>
                <fork>true</fork>
                <meminitial>128m</meminitial>
                <maxmem>512m</maxmem>
                <compilerArgs>
                    <arg>-Xpkginfo:always</arg>
                </compilerArgs>
            </configuration>
        </plugin>

这产生了一个.jar,其中包含所有必需的依赖项,这里包括著名的org/w3c/dom/ls/DocumentLS

部署

现在我将这个.jar 移动到我的服务器并尝试使用以下命令运行它:

java -jar myJar.jar <inputs>

当我这样做时,我再次收到以下异常!

Exception in thread "main" java.lang.NoClassDefFoundError: org/w3c/dom/ls/DocumentLS
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:801)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:699)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:622)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        at org.apache.xerces.jaxp.DocumentBuilderImpl.<init>(Unknown Source)
        at org.apache.xerces.jaxp.DocumentBuilderFactoryImpl.newDocumentBuilder(Unknown Source)
        at com.company.tools.impl.FileProviderImpl.getXmlFile(FileProviderImpl.java:68)
        at com.company.tools.impl.FileProviderImpl.<init>(FileProviderImpl.java:38)
        at com.company.tools.impl.FileProviderImpl$Builder.build(FileProviderImpl.java:91)
        at com.company.tools.Application.main(Application.java:50)
Caused by: java.lang.ClassNotFoundException: org.w3c.dom.ls.DocumentLS
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 15 more

我的问题和一些关于机器的细节

我有点迷路了。我已将依赖项添加到我的pom.xml,该类很好地封装在.jar 中,但我仍然有同样的问题。 我究竟做错了什么?

如果有帮助的话:

我的机器

Java version: 11.0.2-BellSoft, vendor: BellSoft, runtime: C:\jdk-11.0.2
Default locale: fr_FR, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

我的服务器

openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
OS: Linux myServerAddress 3.10.0-327.el7.x86_64 #1 SMP Thu Oct 29 17:29:29 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux

提前致谢!

【问题讨论】:

  • 你可以试试这个版本2.12.0 吗?
  • @Sambit 同样的问题,不幸的是
  • @Sambit 如果我检查修复,我知道他的一些依赖项引用了与所需版本冲突的 xercesImpl 的不同版本。但这不是我的情况,我在 Pom 中基本上没有依赖项,除了 xerces 和 junit 以及范围测试...
  • @Sambit 你终于是对的,答案在你建议的 Github 上的问题中,我只是没有看到它的到来,因为我无法想象该接口正在拉动对实现的传递依赖(+ Maven 中的依赖树没有看到它)。非常感谢!

标签: java maven java-11 xerces


【解决方案1】:

感谢@Sambit 关于this GitHub issue 的第二条评论,我最终找到了解决方案。在这里发布答案,希望它可以节省其他人的头痛!

基本上,我的pom.xml 中有这个:

<dependencies>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xerces</artifactId>
        <version>2.4.0</version>
    </dependency>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xercesImpl</artifactId>
        <version>2.11.0</version>
    </dependency>
</dependencies>

在这两种情况下(单元测试和主代码),此代码都引发了异常:

try(InputStream is = new FileInputStream(file)) {
    documents.put(file.getName(), DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is));
}

...具体来说,通过调用newDocumentBuilder(),它正在寻找DocumentImpl 类型的实现。

问题说明

第一个依赖项xerces 是对已弃用的xercesImpl 版本的传递依赖项。 因此,当我运行测试时,代码正在编译(因为存在依赖项),但是当 newDocumentBuilder() 正在寻找 DocumentImpl 时,执行由正在寻找 org/w3c/dom/ls/DocumentLS 的错误依赖项返回而没有成功,所以提高NoClassDefFoundError

一旦我在我的 pom 中添加了对 xercesImpl 的显式依赖,junit 运行器就会明白,与其在已弃用的 xercesImpl 版本中搜索 DocumentImpl,不如在显式依赖中查找它所以问题解决了。

但是,在服务器上运行程序的 JVM 并没有采用相同的假设:newDocumentBuilder() 仍在传递依赖项中寻找 DocumentImpl,因此问题仍然存在。

分辨率

摆脱传递依赖:

<dependencies>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xerces</artifactId>
        <version>2.4.0</version>
        <exclusions>
            <exclusion>
                <groupId>xerces</groupId>
                <artifactId>xercesImpl</artifactId>
            <exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xercesImpl</artifactId>
        <version>2.11.0</version>
    </dependency>
</dependencies>    

【讨论】:

  • 你也可以只恢复这两个依赖的顺序:xercesxercesImpl2.11.0xercesxerces2.4.0 Maven 接受第一个调用,因此您不需要排除 xercesImpl如果您之前调用过,则在 xerces 中。
  • 太棒了.. 也解决了与我的 spring boot 项目类似的问题
猜你喜欢
  • 2021-05-15
  • 2018-01-25
  • 2021-06-07
  • 2022-08-23
  • 2023-03-22
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2019-12-12
相关资源
最近更新 更多