NoClassDefFoundError: org / w3c / dom / ls / DocumentLS - проблема возникает только при развертывании после исправления во время компиляции - PullRequest
2 голосов
/ 25 мая 2020

Фон

У меня есть проект, в котором я анализирую некоторые 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:

enter image description here

Развертывание

Теперь я перемещаю этот .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

Заранее спасибо!

1 Ответ

1 голос
/ 28 мая 2020

В итоге я нашел решение благодаря второму комментарию @Sambit о этой проблеме GitHub . Публикация ответа здесь в надежде, что это может спасти кого-то еще от головной боли!

По сути, это было в моем 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.

После того, как я добавил явную зависимость к xercesImpl в моем pom, бегун junit понял, что вместо поиска DocumentImpl в устаревшей версии xercesImpl его следовало искать в явная зависимость, поэтому проблема была решена.

Однако 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>    
...