[英]getting 'Could not find or load main class' after adding provided spark .jar dependencies to gradle build
我正在嘗試使用一些提供的依賴項創建一個可執行文件.jar,並且我有一個從“gradle init”創建的簡單示例,在其中我可以在添加幾個提供的依賴項之前執行.jar,但是一旦我添加了這些依賴項就會失敗.
我可以復制如下:
mkdir /tmp/foo
cd /tmp/foo
run 'gradle init'
Select type of project to generate:
2: application
Select implementation language:
3: Java
Select build script DSL:
1: Groovy
Select test framework:
1: JUnit 4
Project name (default: foo):
Source package (default: foo):
然后在 build.gradle 的末尾添加以下內容:
jar {
manifest {
attributes "Main-Class": "foo.App"
}
zip64 = true
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
在命令行中,運行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
你應該看到:
Hello world.
現在將 build.gradle 中的“依賴項”塊更改為以下內容:
configurations {
provided
compile.extendsFrom(provided)
}
dependencies {
implementation 'com.google.guava:guava:29.0-jre'
testImplementation 'junit:junit:4.13'
implementation "org.apache.spark:spark-sql_2.11:2.4.4"
implementation "org.apache.spark:spark-hive_2.11:2.4.4"
}
在命令行,再次運行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
你應該看到一切都很好:
Hello world.
接下來請更換
implementation "org.apache.spark:spark-sql_2.11:2.4.4"
implementation "org.apache.spark:spark-hive_2.11:2.4.4"
和
provided "org.apache.spark:spark-sql_2.11:2.4.4"
provided "org.apache.spark:spark-hive_2.11:2.4.4"
在命令行,再次運行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
這次你會得到:
Error: Could not find or load main class foo.App
所以這顯然是由於試圖讓 Spark 相關的依賴項“提供”,因此不是.jar 的一部分。 但是,您會注意到 class foo.App 非常簡單,與 Spark 無關。 所以,目前很困惑為什么在添加這些類型的依賴項時,主 class 突然變得無法找到。 在此先感謝您的幫助 !
您可能自己已經注意到了(這可能也是您想要的):當您使用provided
(或compile
)而不是在dependencies
項塊中implementation
時,構建的 JAR 文件包含所有依賴項 JARs 的全部內容。
這里的問題是您的jar
任務配置確實從依賴項 JARs 中獲取了所有內容,包括。 他們的META-INF/
目錄文件。 其中一些依賴項 JARs 似乎已簽名,因此在其META-INF/
目錄中包含數字簽名 - 也由您的jar
任務復制。 當運行java -jar …
時,這些簽名會妨礙並導致 class not found 錯誤(即使 class在JAR 中)。
一個簡單的解決方法是在創建 JAR 文件時排除簽名:
jar {
exclude 'META-INF/*.DSA'
}
將 go 歸功於此 SO answer 。
這是一個將 Chriki 的解決方案與也適用於我的 shadowJar 方法相結合的答案。 任你選。 如果這篇文章對您有幫助,請支持 Chriki 的回答。
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building a CLI application.
id 'application'
// This was what I used in my solution
id 'com.github.johnrengelman.shadow' version '5.2.0'
}
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
configurations {
provided
compile.extendsFrom(provided)
}
dependencies {
implementation 'com.google.guava:guava:29.0-jre'
testImplementation 'junit:junit:4.13'
provided "org.apache.spark:spark-sql_2.11:2.4.4"
provided "org.apache.spark:spark-hive_2.11:2.4.4"
}
application {
// Define the main class for the application.
mainClassName = 'foo.App'
}
test {
// Use junit platform for unit tests
useJUnitPlatform()
}
jar {
// Line below does the trick if you are using 'gradlew jar'
// Shout out / big ups to: Chriki
// Note: My solution (using shadow gradle plugin)
// does not require this, but it doesn't hurt
exclude 'META-INF/*.DSA'
manifest {
attributes "Main-Class": "foo.App"
}
zip64 = true
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
// This was the second part of what I used in my solution
// When building, specify: 'gradlew shadowJar' - the jar you want has -all* in it.
// Run with: java -jar build/libs/foo-all.jar
shadowJar {
zip64 = true // I had to specify this twice.. OK.. not gonna lose sleep.
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.