NoClassDefFoundError: org/w3c/dom/ls/DocumentLS - issue occurring only on deployment after having fixed it on compile time
Asked Answered
T

1

12

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:

enter image description here

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!

Talanta answered 25/5, 2020 at 16:3 Comment(5)
Can you try with this version 2.12.0 ?Engird
@Engird same issue, unfortunatelyTalanta
Check this link. github.com/capstone-coal/coal-sds/issues/32.Engird
@Engird if I check the fix made, I understand that he was having some of his dependencies referencing a different version of the xercesImpl which was conflicting with the wanted one. But it’s not my case, I basically have no dependencies in Pom except for xerces and junit with scope test...Talanta
@Engird you were finally right, the answer was in the issue on Github you suggested, I just didn't see it coming as I couldn't imagine the interface was pulling a transitive dependency on the implementation (+ the dependency tree in maven wasn't seeing it). Thanks a lot!Talanta
T
18

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>    
Talanta answered 28/5, 2020 at 13:2 Comment(2)
You can also just revert the order of these two dependencies : <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>xerces</groupId> <artifactId>xerces</artifactId> <version>2.4.0</version> </dependency> Maven takes the first call so you don't need to exclude xercesImpl in xerces if you call it before.Fluker
Great.. solved similar issue to my spring boot project as wellLevesque

© 2022 - 2024 — McMap. All rights reserved.