NoClassDefFoundError во время выполнения с Gradle
я использую gradle в качестве плагина JavaFX.
Все работает отлично даже после строительства и runnig excecutable at распределение/, за исключением одного класса: CloseableHttpClient
для нескольких целей я создаю следующий объект вроде этого:
CloseableHttpClient client = HttpClients.createDefault();
запуск программы в IDE не проблема, все работает нормально. Но если я построю и попытаюсь запустить .EXE-файл, я получаю следующее Throwable
-StackTrace:
java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:955)
at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:58)
at ch.itcb.tools.lom.util.JsonSimpleUtil.http(JsonSimpleUtil.java:29)...
Я действительно не понимать это. Как может быть, что только этот класс не найден,но все мои другие классы?
моя сборка.файл gradle:
apply plugin: 'java'
apply plugin: 'eclipse'
apply from: 'javafx.plugin'
sourceCompatibility = 1.8
version = '0.1'
jar {
manifest {
attributes 'Implementation-Title': 'LogoffManager',
'Implementation-Version': version
}
}
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: 'lib', include: ['*.jar'])
compile 'ch.qos.logback:logback-classic:1.1.3'
compile 'org.apache.httpcomponents:httpclient:4.5.1'
compile 'com.googlecode.json-simple:json-simple:1.1'
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
test {
systemProperties 'property': 'value'
}
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
пожалуйста, напишите комментарий, если вам нужна дополнительная информация. Тнх.
1 ответов
это хороший вопрос, с которым я столкнулся только сейчас, исследуя примеры многих способов разработчиков Java, которые могут закончиться классом path fun: -)
я начал с минимальной версии вашей сборки.gradle (включая только то, что имеет непосредственное отношение), в частности:
plugins {
id 'java'
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
jar {
manifest {
attributes 'Main-Class': 'com.oliverlockwood.Main'
}
}
dependencies {
compile 'org.apache.httpcomponents:httpclient:4.5.1'
}
мой "основной" класс в этом контексте использует ваш пример кода, т. е.:
package com.oliverlockwood;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public class Main {
public static void main(String[] args) {
CloseableHttpClient client = HttpClients.createDefault();
}
}
на этом этапе я могу бежать gradle clean build
следовал по java -jar build/libs/33106520.jar
(мой проект был назван в честь этого StackOverflow вопрос), и я вижу это:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClients
at com.oliverlockwood.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClients
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
это тонко отличается от вашей ошибки, но прежде чем копать и воспроизводить это, позвольте мне подчеркнуть кое-что: и эта ошибка, и та, которую вы видите, вызваны во время выполнения, когда загрузчик классов не может найти класс, который ему нужен. Там довольно хороший пост в блоге здесь С некоторыми более подробными сведениями о разнице между classpath во время компиляции и runtime classpaths.
если я запускаю gradle dependencies
I показаны зависимости времени выполнения для моего проекта:
runtime - Runtime classpath for source set 'main'.
\--- org.apache.httpcomponents:httpclient:4.5.1
+--- org.apache.httpcomponents:httpcore:4.4.3
+--- commons-logging:commons-logging:1.2
\--- commons-codec:commons-codec:1.9
я добавил их вручную один за другим в свой путь к классам среды выполнения. (Для справки, это обычно не считается хорошей практикой; но ради эксперимента я скопировал эти банки в свой build/libs
папка и побежал с java -cp build/libs/33106520.jar:build/libs/* com.oliverlockwood.Main
. Интересно, что это не смогло воспроизвести вашу точную проблему. Напомним:
- без
org.apache.httpcomponents:httpclient
доступно во время выполнения, то мы терпим неудачу, потому чтоHttpClients
jar не найдено. - С
org.apache.httpcomponents:httpclient:4.5.1
доступно во время выполнения, тогда ваша проблема не проявляется - и я отмечаю, что класс, который ваша сборка не может найти (org.apache.http.conn.ssl.SSLConnectionSocketFactory
) составляет часть этой же библиотеки Apache, что действительно очень подозрительно.
я подозреваю, что ваш путь к классам среды выполнения содержит разные версии библиотеки Apache httpclient. Поскольку существует множество версий, я не собираюсь тестировать каждую из них комбинация, поэтому я вместо этого оставлю вам следующий совет.
- если вы хотите полностью понять основную причину вашей проблемы, то определите ровно какие банки (включая их версии) присутствуют в вашем пути к классам времени выполнения ошибок, включая любые банки, которые упакованы внутри вашего, если вы создаете жирную банку (подробнее об этом в пункте 3). Было бы здорово, если бы вы поделились этими деталями здесь; анализ первопричин обычно помогает всем понять лучше :-)
- по возможности избегайте использования зависимостей в виде
compile fileTree(dir: 'lib', include: ['*.jar'])
. Управляемые зависимости, основанные на репозитории, таком как Maven или JCenter, намного проще работать последовательно, чем зависимости в случайном каталоге. Если это внутренние библиотеки, которые вы не хотите публиковать в репозитории артефактов с открытым исходным кодом, то, возможно, стоит настроить локальный экземпляр Nexus или аналогичный. - рассмотрите возможность производства "жирной банки" вместо " тонкой банки" - это означает, что все зависимости времени выполнения упакованы в jar, который вы строите. Есть хороший теневой плагин для Gradle что я бы рекомендовал - с этим на месте в моем
build.gradle
и под управлениемgradle clean shadow
, я смог запуститьjava -jar
просто отлично, без необходимости вручную добавлять что-либо в мой путь к классам.