这里我提供 Kotlin DSL (build.gradle.kts) 的解决方案。
注意前3个方法修改了Gradle现有的Jar任务。
方法一:将库文件放在结果JAR旁边
此方法不需要application或任何其他插件。
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
manifest.attributes["Class-Path"] = configurations
.runtimeClasspath
.get()
.joinToString(separator = " ") { file ->
"libs/${file.name}"
}
}
请注意,Java 要求我们为 Class-Path 属性使用相对 URL。因此,我们不能使用 Gradle 依赖项的绝对路径(这也容易被更改并且在其他系统上不可用)。如果你想使用绝对路径,也许this workaround 可以。
使用以下命令创建 JAR:
./gradlew jar
默认会在build/libs/目录中创建结果JAR。
创建 JAR 后,将库 JAR 复制到放置结果 JAR 的 libs/ 子目录中。确保您的库 JAR 文件的文件名中不包含空格(其文件名应与上述任务中${file.name} 变量指定的文件名匹配)。
方法 2:在结果 JAR 文件中嵌入库(fat 或 uber JAR)
此方法也不需要任何 Gradle 插件。
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
}
创建 JAR 与之前的方法完全相同。
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 documentations。
方法四:新建任务(而不是修改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())
}
运行创建的 JAR
java -jar my-artifact.jar
以上解决方案经过以下测试:
- Java 17
- Gradle 7.1(将 Kotlin 1.4.31 用于 .kts 构建脚本)
见官方Gradle documentation for creating uber (fat) JARs。
有关清单的更多信息,请参阅Oracle Java Documentation: Working with Manifest files。
有关tasks.create() 和tasks.register() 之间的区别,请参阅this post。
注意您的resource files will be included in the JAR file automatically(假设它们被放置在/src/main/resources/ 目录或构建文件中设置为资源根目录的任何自定义目录中)。要访问应用程序中的资源文件,请使用以下代码(注意名称开头的 /):
- 科特林
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()
- Java
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"));