2015-10-13 29 views
7

Używam gradle jako wtyczki JavaFX. Wszystko działa doskonale nawet po zakończeniu budowy i runnig ten excecutable na dystrybucji/, z wyjątkiem jednej klasy: CloseableHttpClientNoClassDefFoundError w środowisku wykonawczym z Gradle

do różnych celów tworzę następujący obiekt tak:

CloseableHttpClient client = HttpClients.createDefault(); 

uruchomienie programu w IDE nie stanowi problemu, wszystko działa dobrze. Ale jeśli zbudować i spróbować uruchomić plik .exe-pojawia się następujący 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)... 

ja naprawdę nie rozumiem tego. Jak to możliwe, że nie można znaleźć tej klasy, ale wszystkie inne moje klasy?

Mój plik build.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' 
     } 
    } 
} 

Proszę napisać komentarz, jeśli potrzebują Państwo więcej informacji. Dzięki.

+0

Proszę udostępnić swój plik build.gradle. – Opal

+0

@Opal done. wciąż nie znaleziono rozwiązania:/ – jntme

+0

Czy jar apache jest w dystrybucji? Czy zawiera brakującą klasę? –

Odpowiedz

7

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ę.

  1. 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ć :-)
  2. 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ą.
  3. 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.
+0

Mam 'java.lang.NoClassDefFoundError: org/apache/http/config/Lookup'. Wciąż szukałem obecności tej klasy wewnątrz JARów Apache Http (httpclient, httpcore) pod 'Maven Dependencies' w Eclipse i nie znalazłem ich. Zdałem sobie sprawę, że maven postanowił rozwiązać inną wersję 'httpcore' z nadrzędnego POM zamiast wersji' httpcore', która jest bezpośrednią zależnością 'httpclient'. Powinien dać jawną wersję' httpcore', która pasuje do tej samej wersji co wersja bezpośredniej zależności 'httpclient'. – user104309

Powiązane problemy