NoClassDefFoundError: org/w3c/dom/ls/DocumentLS - issue occurring only on deployment after having fixed it on compile time
NoClassDefFoundError: org/w3c/dom/ls/DocumentLS - issue occurring only on deployment after having fixed it on compile time
背景
我有一个项目,我在其中解析一些 XML 文档,我碰巧需要 xerces
依赖项:
<dependency>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.4.0</version>
</dependency>
在使用 junit4
编写单元测试时,我每次 运行 进行单元测试时都会遇到问题,每次使用 [=21] 进行编译时都会出现以下问题=]:
[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
,class 很好地打包在 .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
提前致谢!
感谢@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
runner 就会理解,而不是在 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>
背景
我有一个项目,我在其中解析一些 XML 文档,我碰巧需要 xerces
依赖项:
<dependency>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.4.0</version>
</dependency>
在使用 junit4
编写单元测试时,我每次 运行 进行单元测试时都会遇到问题,每次使用 [=21] 进行编译时都会出现以下问题=]:
[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
,class 很好地打包在 .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
提前致谢!
感谢@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
runner 就会理解,而不是在 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>