簡體   English   中英

Java 不從清單定義的類路徑加載類

[英]Java doesn't load classes from manifest-defined classpath

我正在使用 Gradle 構建一個項目。 這是我的build.gradle

plugins { id 'application' }

group 'my.group'
version '1.0'

sourceCompatibility = 1.11

repositories { mavenCentral() }

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.7.2'
}

mainClassName = 'my.group.App'

jar {
    manifest {
        attributes(
            'Main-Class': mainClassName,
            'Class-Path': configurations.runtimeClasspath.files.collect { it.name }.join(' ')
        )
    }

    from configurations.runtimeClasspath
    into ''
}

這會正確生成一個帶有以下 META-INF/MANIFEST.MF 的 jar 文件:

Manifest-Version: 1.0
Main-Class: my.group.App
Class-Path: sqlite-jdbc-3.7.2.jar
[newline]

並且在這個jar文件的根目錄下,確實有sqlite-jdbc-3.7.2.jar引用的sqlite-jdbc-3.7.2.jar文件; 我手動驗證了在這個 jar 文件中有一個名為org.sqlite.JDBC的類。

但是,使用java -jar jarfile.jar運行生成的 jar java -jar jarfile.jar導致:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at my.group.LEManagerSqlite.<init>(LEManagerSqlite.java:64)
        at my.group.LEManager.createLEManager(LEManager.java:80)
        at my.group.GuiFrame.<init>(GuiFrame.java:60)
        at my.group.App.openFromFile(App.java:23)
        at my.group.App.main(App.java:19)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.sqlite.JDBC
        at my.group.SqliteConnectionManager.<clinit>(SqliteConnectionManager.java:17)
        ... 5 more
Caused by: java.lang.ClassNotFoundException: org.sqlite.JDBC
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        at my.group.SqliteConnectionManager.<clinit>(SqliteConnectionManager.java:14)
        ... 5 more

作為參考, SqliteConnectionManager有一個靜態初始值設定項,它加載org.sqlite.JDBC ,這是在堆棧跟蹤中被引用為SqliteConnectionManager.java:14的內容:

Class.forName("org.sqlite.JDBC");

我使用 OpenJDK 11 和 OpenJ9 11 對此進行了測試,結果相同。 我得出結論,我做錯了什么,但我不明白是什么。

我發現我做錯了什么:文檔清楚地說明(doh!) Class-Path指令在本地文件系統或網絡中查找其他類路徑資源。

JVM 不支持從包含在主 jar 文件中的 jar 文件加載其他類,因此需要自定義加載代碼。 一個更簡單的替代方法是從 jar 文件中解壓縮額外的類並直接包含它們。 以這種方式構建的 jar 文件稱為“fat jar”(或“uber jar”)。

有一個叫做 Shadow 的 Gradle 插件,它可以在沒有任何進一步配置的情況下構建這樣的 jars。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM