Issue
Background
I have a project where I parse some XML documents and I happened to need the xerces
dependency:
<dependency>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.4.0</version>
</dependency>
While writing the unit tests with junit4
, I had an issue every time I was running a unit test, which was the following and occurring every time I was compiling with 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)
Compile-time solution
Searching the web, I have realized that I needed to add a new dependency to my pom.xml
:
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.11.0</version>
</dependency>
After doing this, the tests compiled fine and I could produce my .jar
which was packaged with the following build plug-in:
<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>
... and compiled with the following settings:
<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>
This produced a .jar
which contains all the required dependencies, here including the famous org/w3c/dom/ls/DocumentLS
:
Deployment
Now I move this .jar
into my server and try to run it with the following command:
java -jar myJar.jar <inputs>
When I do that, I get the following exception, again!
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
My question and some details about the machines
I am a bit lost here. I've added the dependency to my pom.xml
, the class is well packaged inside the .jar
, but still I have the same issue.
What am I doing wrong?
If it can help:
My machine:
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"
My server:
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
Thanks in advance!
Solution
I ended up finding the solution thanks to @Sambit second comment about this GitHub issue. Posting the answer here hoping it can save someone else days of headache!
Basically, I had this in my 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>
In both cases (unit test and main code), the exception was raised by this code:
try(InputStream is = new FileInputStream(file)) {
documents.put(file.getName(), DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is));
}
... specifically, by the call to newDocumentBuilder()
which was looking for an implementation of type DocumentImpl
.
Issue explanation
The first dependency xerces
is pulling a transitive dependency on a deprecated version of xercesImpl
.
Hence, when I was running my tests, the code was compiling (because the dependency was there) but when the newDocumentBuilder()
was looking for the DocumentImpl
, the implementation was returned by the bad dependency which was looking for org/w3c/dom/ls/DocumentLS
without success, so raising the NoClassDefFoundError
.
Once I added the explicit dependency to xercesImpl
in my pom, the junit
runner understood that instead of searching the DocumentImpl
in the deprecated version of xercesImpl
, it should have been looked for in the explicit dependency so the issue was solved.
However, the JVM running the program on the server wasn't taking the same assumption: the newDocumentBuilder()
was still looking for DocumentImpl
inside the transitive dependency, so the issue was still there.
Resolution
Get rid of the transitive dependency:
<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>
Answered By - Matteo NNZ
Answer Checked By - Mary Flores (JavaFixing Volunteer)