使用Gradle构建带有依赖的JAR文件

165

我有一个多项目构建,我在其中一个子项目中放置了一个构建fat JAR的任务。我创建的任务类似于这个cookbook中描述的任务。

jar {
  from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  manifest { attributes 'Main-Class': 'com.benmccann.gradle.test.WebServer' }
}

运行时会出现以下错误:

原因:您无法更改未解决状态的配置!

我不确定这个错误是什么意思。我还在Gradle JIRA上报告了这个问题,以防它是一个错误。


1
有关 Kotlin DSL(build.gradle.kts)的完整答案,请参见此帖子 - Mahozad
1
这个回答解决了你的问题吗?使用Gradle创建可运行的JAR - Mahozad
https://www.baeldung.com/gradle-fat-jar - k4dima
19个回答

2

2

这是针对Kotlin DSL(build.gradle.kts)的。

方法1(无需application或其他插件)

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
    // OR another notation
    // manifest {
    //     attributes["Main-Class"] = "com.example.MyMainClass"
    // }
}

如果您使用任何外部库,请使用以下代码。将库JAR文件复制到放置结果JAR文件的 libs 子目录中。请确保您的库JAR文件名称中不包含空格。
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属性中使用相对路径。因此,我们不能使用Gradle依赖项的绝对路径(这也容易更改并且不可用于其他系统)。如果您想使用绝对路径,也许this workaround可以解决问题。
使用以下命令创建JAR文件:
./gradlew jar

默认情况下,结果JAR将在build/libs/目录中创建。

方法2:将库(如果有)嵌入到结果JAR中(fat或uber 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
}

创建 JAR 文件的方法与之前的方法完全相同。

方法 3:使用 Shadow 插件(创建 fat 或 uber JAR)

plugins {
    id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these will be reflected for Shadow as well
tasks.jar {
    manifest.attributes["Main-Class"] = "org.example.MainKt"
}

使用以下命令创建JAR文件:

./gradlew shadowJar

请参阅Shadow文档以获取有关配置插件的更多信息。

运行创建的JAR文件

java -jar my-artifact.jar

以上解决方案已经测试过:

  • Java 17
  • Gradle 7.1(使用 Kotlin 1.4.31 来编写 .kts 构建脚本)

请参阅官方 Gradle 文档以创建 uber (fat) JARs

有关清单的更多信息,请参见 Oracle Java 文档:使用清单文件

请注意,您的资源文件将自动包含在 JAR 文件中(假设它们放置在 /src/main/resources/ 目录或在构建文件中设置为资源根目录的任何自定义目录中)。要访问应用程序中的资源文件,请使用此代码(请注意名称开头的 /):

  • Kotlin
    val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText()
    // 其他方式:
    // 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();
    // 或者 var stream = MyClass.class.getResourceAsStream("/vegetables.txt");
    var reader = new BufferedReader(new InputStreamReader(stream));
    var vegetables = reader.lines().collect(Collectors.joining("\n"));
    

1
在Gradle构建的jar文件中排除不需要的清单条目可以解决MainClass文件未找到的错误。
jar{
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
    from {
      -----
    }
}

1
对于那些需要从项目中构建多个jar的人。
在gradle中创建一个函数:
void jarFactory(Jar jarTask, jarName, mainClass) {
    jarTask.doFirst {
        println 'Build jar ' + jarTask.name + + ' started'
    }

    jarTask.manifest {
        attributes(
                'Main-Class':  mainClass
        )
    }
    jarTask.classifier = 'all'
    jarTask.baseName = jarName
    jarTask.from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
    {
        exclude "META-INF/*.SF"
        exclude "META-INF/*.DSA"
        exclude "META-INF/*.RSA"
    }
    jarTask.with jar 
    jarTask.doFirst {
        println 'Build jar ' + jarTask.name + ' ended'
    }
}

然后调用:
task makeMyJar(type: Jar) {
    jarFactory(it, 'MyJar', 'org.company.MainClass')
}

适用于Gradle 5。

Jar文件将被放置在./build/libs目录下。


1

我使用插件 com.github.jengelman.gradle.plugins:shadow:5.2.0 来执行任务 shadowJar

使用方法:只需运行 ./gradlew app::shadowJar,生成的文件将位于 MyProject/app/build/libs/shadow.jar

顶层 build.gradle 文件:

 apply plugin: 'kotlin'

buildscript {
    ext.kotlin_version = '1.3.61'

    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
    }
}

应用程序模块级别的 build.gradle 文件。
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'

sourceCompatibility = 1.8

kapt {
    generateStubs = true
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"
    shadow "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"

    implementation project(":module_remote")
    shadow project(":module_remote")
}

jar {
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
    manifest {
        attributes(
                'Main-Class': 'com.github.kolyall.TheApplication',
                'Class-Path': configurations.compile.files.collect { "lib/$it.name" }.join(' ')
        )
    }
}

shadowJar {
    baseName = 'shadow'
    classifier = ''
    archiveVersion = ''
    mainClassName = 'com.github.kolyall.TheApplication'

    mergeServiceFiles()
}


0

如果"compile"和"implementation"无法使用,请尝试使用"runtimeClasspath"。

jar {
    manifest {
        attributes "Main-Class": "com.example.app"
    }

    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

0

Gradle 6.3,Java库。当运行“gradle build”任务时,“jar任务”的代码将依赖项添加到“build/libs/xyz.jar”中。

plugins {
    id 'java-library'
}

jar {
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

0

关于这种解决方案,有一些需要记住的事情:

task fatJar(type: Jar) {
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

只要您使用“编译”依赖项,它就可以工作。如果您使用“实现”依赖项,则无法正常工作。

-1

如果你已经习惯了使用Ant,那么你也可以尝试使用Gradle:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接