【问题标题】:How to create a Fat JAR with the Kotlin DSL?如何使用 Kotlin DSL 创建 Fat JAR?
【发布时间】:2019-07-19 17:24:42
【问题描述】:

我正在使用 Gradle 5.5。我有一个基于 Groovy 的构建脚本,正在尝试迁移到 Kotlin DSL。 jar 任务包含将所有依赖项复制到 JAR 文件的典型行:

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

我找不到将此行转换为 Kotlin DSL 的方法。

让我给你一些背景。这是我最初的基于 Groovy 的构建脚本:

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.3.41"
}

group = "com.rhubarb_lip_sync"
version = "1.0.0"

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile "com.beust:klaxon:5.0.1"
    compile "org.apache.commons:commons-lang3:3.9"
    compile "no.tornado:tornadofx:1.7.19"
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

jar {
    manifest {
        attributes "Main-Class": "com.rhubarb_lip_sync.rhubarb_for_spine.MainKt"
    }

    // This line of code recursively collects and copies all of a project"s files
    // and adds them to the JAR itself. One can extend this task, to skip certain 
    // files or particular types at will
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

这是我基于 Kotlin 的构建脚本。它工作正常,除了那一行:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.3.41"
}

group = "com.rhubarb_lip_sync"
version = "1.0.0"

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
    implementation("com.beust:klaxon:5.0.1")
    implementation("org.apache.commons:commons-lang3:3.9")
    implementation("no.tornado:tornadofx:1.7.19")
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

tasks.withType<Jar> {
    manifest {
        attributes("Main-Class" to "com.rhubarb_lip_sync.rhubarb_for_spine.MainKt")
    }

    // ?
}

【问题讨论】:

标签: java gradle kotlin


【解决方案1】:

collect() 在 groovy 中是 map() 在 Kotlin 中。

groovy 的三元运算符在 Kotlin 中可以转换为 if。

主要区别在于 Kotlin 中的configurations.compile 不是Configuration,而是Provider&lt;Configuration&gt;。所以要么你 get 提供者的配置,要么你通过 mapping 提供者到另一个提供者来保持懒惰。所以我认为它应该工作

from(configurations.compileClasspath.get().map { if (it.isDirectory()) it else zipTree(it) })

或

from(configurations.compileClasspath.map { config -> config.map { if (it.isDirectory) it else zipTree(it) } })

请注意,compile 已被弃用很长时间。由于现在使用implementation 来声明您的依赖项,因此编译配置中没有任何内容了,您必须将依赖项从compileClasspath 中取出来构建您的超级jar。

【讨论】:

  • 感谢您的解释!您的两个 sn-ps 在语法上都是正确的,但似乎都不起作用。在这两种情况下,我最终都会得到一个没有依赖关系的苗条 JAR。
  • 我刚刚意识到 Slaw 上面的评论有效,与您的代码的唯一区别是他使用 configurations.compileClasspath 而不是 configurations.compile。显然,后者不仅已被弃用,而且工作方式也有所不同。
  • 我没有注意到您已经切换到实现来声明您的依赖项。因此它们不再是已弃用的编译配置的一部分,这就是您需要使用 compileClasspath 的原因。
  • 现在我明白了。非常感谢你。如果其他开发人员处于相同情况并且没有意识到从 compile 移动到 implementation 会破坏 JAR 目标,也许您可​​以将此信息移至您的答案。
  • 谢谢。此外,如果有人收到错误:出了什么问题:任务“:jar”的执行失败。 > 入口 META-INF/services/io.ktor.client.HttpClientEngineContainer 是重复但未设置重复处理策略。详情请参考docs.gradle.org/7.2/dsl/…。 可以通过以下方式解决:duplicatesStrategy = DuplicatesStrategy.EXCLUDE
【解决方案2】:

这是 Maksim Kostromin的一个很好的示例

val mainClass = "com.myproject" // Replace this, your project main name

tasks {
  register("fatJar", Jar::class.java) {
    archiveClassifier.set("all")
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    manifest {
      attributes("Main-Class" to mainClass)
    }
    from(configurations.runtimeClasspath.get()
        .onEach { println("add from dependencies: ${it.name}") }
        .map { if (it.isDirectory) it else zipTree(it) })
    val sourcesMain = sourceSets.main.get()
    sourcesMain.allSource.forEach { println("add from sources: ${it.name}") }
    from(sourcesMain.output)
  }
}

【讨论】:

  • 这是唯一对我有用的解决方案。非常感谢!
猜你喜欢
  • 2019-08-29
  • 2020-07-29
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 2019-12-01
  • 2019-03-06
  • 1970-01-01
相关资源
最近更新 更多