19

JavaFX プラグインとして gradle を使用しています。1 つのクラスを除いて、ディストリビューション/で実行可能ファイルをビルドして実行した後でも、すべてが完全に機能します。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)...

私は本当にそれを理解していません。このクラスだけが見つからないのに、他のすべてのクラスが見つかるというのはどうしてでしょうか?

私の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'
       }
    }
}

さらに情報が必要な場合は、コメントを書いてください。どうも。

4

3 に答える 3

25

これは良い質問です。Java 開発者がクラス パスを楽しくする方法の例を調べているときに、ちょうど今出くわしました :-)

具体的には、build.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)

これはあなたのエラーとは微妙に異なりますが、それを掘り下げて再現する前に、何か強調させてください. コンパイル時のクラスパスと実行時のクラスパスの違いに関する詳細が記載された、非常に優れたブログ投稿がここにあります。

実行gradle dependenciesすると、プロジェクトのランタイム依存関係を確認できます。

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

これらをランタイム クラスパスに 1 つずつ手動で追加しました。(記録として、これは一般的に良い習慣とは見なされていませんが、実験のために、これらのjarファイルを自分のbuild/libsフォルダーにコピーして実行しましたjava -cp build/libs/33106520.jar:build/libs/* com.oliverlockwood.Main。興味深いことに、これは正確な問題を再現できませんでした。要約すると:

  • org.apache.httpcomponents:httpclient実行時に利用できない場合、 HttpClientsjar が見つからないため失敗します。
  • 実行時にorg.apache.httpcomponents:httpclient:4.5.1利用可能である場合、問題は発生しません。ビルドで見つからないクラス ( org.apache.http.conn.ssl.SSLConnectionSocketFactory) は、この同じ Apache ライブラリの一部であり、非常に疑わしいことに注意してください。

私の疑いは、実行時クラスパスに別のバージョンの Apache httpclient ライブラリが含まれていることです。そこにはたくさんのバージョンがあるので、すべての組み合わせをテストするつもりはないので、代わりに次のアドバイスを残します.

  1. 問題の根本原因を完全に理解したい場合は、エラー ケースのランタイム クラスパスに存在する jar (バージョンを含む) を正確に特定します。これについてはポイント 3) で詳しく説明します。これらの詳細をここで共有していただければ幸いです。根本原因分析は通常、誰もがよりよく理解するのに役立ちます:-)
  2. 可能であれば、依存関係を のように使用することは避けてくださいcompile fileTree(dir: 'lib', include: ['*.jar'])。Maven や JCenter などのリポジトリに基づく管理された依存関係は、ランダムなディレクトリ内の依存関係よりも一貫して作業するのがはるかに簡単です。これらがオープンソースのアーティファクト リポジトリに公開したくない内部ライブラリである場合は、ローカルの Nexus インスタンスなどをセットアップする価値があるかもしれません。
  3. 「薄い jar」ではなく「太い jar」を作成することを検討してください。これは、すべてのランタイム依存関係がビルドした jar にパッケージ化されることを意味します。私がお勧めする Gradle 用の優れたShadow プラグインがあります。これを に配置してbuild.gradle実行すると、手動でクラスパスに何も追加しなくても問題なくgradle clean shadow実行できました。java -jar
于 2016-02-09T23:10:15.487 に答える
0

Spring ブート ユーザーの場合、これは 1 行のコードで解決できます。私はを使用してGradle/Kotlinいるので:

id("org.springframework.boot") version "2.5.5"

plugins {}build.gradle.ktsのセクション内

詳細については、Spring Boot Gradle プラグイン リファレンス ガイドを参照してください。

于 2021-10-01T07:00:58.057 に答える