我在Gradle 4.6中有一个简单的项目,希望将其制作成可执行的JAR文件。我尝试了shadow
、gradle-fatjar-plugin
、gradle-one-jar
、spring-boot-gradle-plugin
插件,但它们都没有添加我的依赖项,这些依赖项被声明为implementation
(没有使用compile
)。对于gradle-one-jar
插件,使用compile
可以工作,但我想要使用implementation
依赖项。
我在Gradle 4.6中有一个简单的项目,希望将其制作成可执行的JAR文件。我尝试了shadow
、gradle-fatjar-plugin
、gradle-one-jar
、spring-boot-gradle-plugin
插件,但它们都没有添加我的依赖项,这些依赖项被声明为implementation
(没有使用compile
)。对于gradle-one-jar
插件,使用compile
可以工作,但我想要使用implementation
依赖项。
jar {
manifest {
attributes(
'Main-Class': 'com.package.YourClass'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
请确保将com.package.YourClass
替换为包含static void main( String args[] )
方法的完全限定类名。
这将打包运行时依赖项。如果需要更多信息,请查看文档。
build/libs
目录下。 - Shayan Toqraeeconfigurations.compileClasspath.filter{ it.exists() }.collect { it.isDirectory() ? it : zipTree(it) }
。这样,如果您有不存在的类路径条目,它也不会卡住。我正在使用Kotlin,因此java源代码类路径条目没有任何内容,导致出现了一些问题。 - Alex Ives根据被接受的答案,我需要再添加一行代码:
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.yourpackage.Main'
}
archiveClassifier = "all"
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
}
没有这个额外的行,它会忽略我的源文件,只添加依赖项:
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
对于较新的Gradle(7+),您可能会看到此错误:
Execution failed for task ':fatJar'.
> Entry [some entry here] is a duplicate but no duplicate handling strategy has been set. Please
refer to https://docs.gradle.org/7.1/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy
for details.
如果发生这种情况,请在fatJar
任务中添加一个duplicatesStrategy
,例如duplicatesStrategy "exclude"
。
同样地,在 Gradle 7+ 中,您只需删除configuration.compile.collect
行,因为它不再是此版本Gradle中的有效配置。
可以使用Gradle Kotlin DSL以类似的方式完成相同的任务:
val jar by tasks.getting(Jar::class) {
manifest {
attributes["Main-Class"] = "com.package.YourClass"
}
from(configurations
.runtime
// .get() // uncomment this on Gradle 6+
// .files
.map { if (it.isDirectory) it else zipTree(it) })
}
之前的回答现在有点过时了,这里有一个使用Gradle-7.4有效的方法:如何使用Gradle Kotlin脚本创建Fat JAR?
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree) // OR .map { zipTree(it) }
from(dependencies)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
在这里,我为 Kotlin DSL(build.gradle.kts)提供解决方案。
请注意,前三种方法修改了Gradle的现有Jar
任务。
此方法不需要application
或任何其他插件。
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
manifest.attributes["Class-Path"] = configurations
.runtimeClasspath
.get()
.joinToString(separator = " ") { file ->
"libs/${file.name}"
}
}
./gradlew jar
${file.name}
变量匹配)。tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree) // OR .map { zipTree(it) }
from(dependencies)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
plugins {
id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these configs are reflected for Shadow as well
tasks.jar {
manifest.attributes["Main-Class"] = "org.example.MainKt"
}
使用此命令创建JAR文件:
./gradlew shadowJar
请参阅Shadow文档以获取有关配置插件的更多信息。
Jar
任务)tasks.create("MyFatJar", Jar::class) {
group = "my tasks" // OR, for example, "build"
description = "Creates a self-contained fat JAR of the application that can be run."
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree)
from(dependencies)
with(tasks.jar.get())
}
java -jar my-artifact.jar
以上解决方案已经测试过,使用以下版本:
请查看官方 Gradle 文档以创建 uber (fat) JARs。
有关清单的更多信息,请参阅 Oracle Java 文档:使用清单文件。
有关 tasks.create()
和 tasks.register()
之间的区别,请参见 此帖子。
/
):
val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText()
// Alternative ways:
// val vegetables = object{}.javaClass.getResource("/vegetables.txt").readText()
// val vegetables = MyClass::class.java.getResourceAsStream("/vegetables.txt").reader().readText()
// val vegetables = object{}.javaClass.getResourceAsStream("/vegetables.txt").reader().readText()
var stream = MyClass.class.getResource("/vegetables.txt").openStream();
// OR var stream = MyClass.class.getResourceAsStream("/vegetables.txt");
var reader = new BufferedReader(new InputStreamReader(stream));
var vegetables = reader.lines().collect(Collectors.joining("\n"));
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
这行代码对我来说是至关重要的。
mainClassName = 'Main'
sourceSets {
main {
java {
srcDirs 'src/main/java', 'src/main/resources'
}
}
}
jar{
manifest {
attributes(
"Main-Class": "$mainClassName",
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it)
}
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn ('dependencies')
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
val main = sourceSets.main.get()
//TODO
register<Jar>("buildFatJar") {
group = "app-backend"
dependsOn(build)
// shouldRunAfter(parent!!.tasks["prepCopyJsBundleToKtor"]) -> This is for incorporating KotlinJS gradle subproject resulting js file.
manifest {
attributes["Main-Class"] = "com.app.app.BackendAppKt"
}
from(configurations.compileClasspath.get().files.map { if (it.isDirectory) it else zipTree(it) })
with(jar.get() as CopySpec)
archiveBaseName.set("${project.name}-fat")
}
}