to jest dobre pytanie, które natknąłem się właśnie podczas badania przykłady wielu sposobów, programiści Java mogą skończyć ze ścieżki klasy zabawy :-)
zacząłem z minimalną wersją swojej build.gradle (w tym tylko, co bezpośrednio dotyczy), w szczególności:
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'
}
My 'main' klasy, w tym kontekście używa przykład kodu, tj:
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();
}
}
na tym etapie Mogę uruchomić gradle clean build
następnie java -jar build/libs/33106520.jar
(mój projekt został nazwany po tym StackOverflow pytanie) i widzę to:
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)
Jest subtelnie różni się od błędów, ale zanim będziemy kopać i reprodukować, że pozwolę sobie podkreślić coś : zarówno ten błąd, jak i ten, który widzisz, są powodowane w środowisku wykonawczym, gdy program ładujący klasy nie może znaleźć wymaganej klasy. Jest całkiem dobry wpis na blogu here z kilkoma dodatkowymi informacjami na temat różnicy między ścieżkami klas kompilacji i ścieżkami klas czasu wykonywania.
Jeśli biegnę gradle dependencies
widzę zależności uruchomieniowe dla mojego projektu:
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
dodałem je ręcznie jeden po drugim do mojego wykonawczego ścieżce klasy. (Dla przypomnienia, nie jest to ogólnie uważane za dobrą praktykę, ale ze względu na eksperyment skopiowałem te słoiki do mojego folderu build/libs
i pobrałem z java -cp build/libs/33106520.jar:build/libs/* com.oliverlockwood.Main
. Co ciekawe, nie było to w stanie odtworzyć dokładnego problemu. podsumowanie:
- Bez
org.apache.httpcomponents:httpclient
dostępne przy starcie, to nie dlatego, że HttpClients
słoik nie znaleziono
- Z
org.apache.httpcomponents:httpclient:4.5.1
dostępnej w czasie wykonywania, to twój problem nie manifest - i pamiętać, że klasa Twój build zawiedzie. aby znaleźć (org.apache.http.conn.ssl.SSLConnectionSocketFactory
) jest część tej samej biblioteki Apache, co jest bardzo podejrzane.
Moje podejrzenie jest wtedy ścieżce klas Runtime zawiera inną wersję z Apache httpclient biblioteki. Ponieważ jest tam wiele wersji, nie będę testować każdej kombinacji, więc opowiem ci następującą radę.
- Jeśli chcesz, aby w pełni zrozumieć przyczynę problemu, a następnie zidentyfikować dokładnie które słoików (włącznie z ich wersjami) są obecne w błąd case wykonawczego ścieżki klasy, w tym wszelkich słoikach, które są zapakowane w twoim jeśli tworzysz gruby słoik (więcej na ten temat w punkcie 3). Byłoby wspaniale, gdybyś podzielił się tymi szczegółami tutaj; Analiza przyczyn źródłowych zwykle pomaga wszystkim lepiej zrozumieć :-)
- Tam, gdzie to możliwe, unikaj używania zależności w sposób zgodny z
compile fileTree(dir: 'lib', include: ['*.jar'])
. Zarządzane zależności oparte na repozytorium, takim jak Maven lub JCenter, są znacznie łatwiejsze w pracy niż spójność w przypadkowym katalogu. Jeśli są to biblioteki wewnętrzne, których nie chcesz publikować w repozytorium open source, może warto zainstalować lokalną instancję Nexus lub podobną.
- Rozważ stworzenie "grubego słoika" zamiast "cienkiego słoika" - oznacza to, że wszystkie zależności środowiska wykonawczego są spakowane w tworzonym słoiku. Jest dobry Shadow plugin for Gradle, który polecam - z tym w moim
build.gradle
i działającym gradle clean shadow
, udało mi się uruchomić java -jar
dobrze, bez konieczności ręcznego dodawania czegokolwiek do mojej ścieżki klas.
Proszę udostępnić swój plik build.gradle. – Opal
@Opal done. wciąż nie znaleziono rozwiązania:/ – jntme
Czy jar apache jest w dystrybucji? Czy zawiera brakującą klasę? –