Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 322
Matteo NNZ Avatar asked May 25 '20 16:05

Matteo NNZ


1 Answers

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>    
like image 82
Matteo NNZ Avatar answered Oct 09 '22 16:10

Matteo NNZ