使用Gradle构建uberjar

42

我想构建一个Uber JAR(也叫fat jar),其中包含项目的所有传递依赖项。我需要在build.gradle文件中添加哪些行?

这是我当前拥有的:

task uberjar(type: Jar) {
    from files(sourceSets.main.output.classesDir)

    manifest {
        attributes 'Implementation-Title': 'Foobar',
                'Implementation-Version': version,
                'Built-By': System.getProperty('user.name'),
                'Built-Date': new Date(),
                'Built-JDK': System.getProperty('java.version'),
                'Main-Class': mainClassName
    }
}

3
你可以尝试使用应用程序插件代替。 - Scott
只要您没有任何依赖项,这将起作用。但是一旦您的项目有了依赖项,它们就不会捆绑到超级jar中。 - Stefan Neuhaus
4个回答

42

我将 task uberjar(.. 替换为以下内容:

jar {
    from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
        exclude "META-INF/*.SF"
        exclude "META-INF/*.DSA"
        exclude "META-INF/*.RSA"
    }

    manifest {
        attributes 'Implementation-Title': 'Foobar',
                'Implementation-Version': version,
                'Built-By': System.getProperty('user.name'),
                'Built-Date': new Date(),
                'Built-JDK': System.getProperty('java.version'),
                'Main-Class': mainClassName
    }
}

如果没有这些排除项,您将会遇到这个问题。


5
我认为应该使用configurations.runtime来包含所有的运行时依赖。 - lyomi
我需要在清单文件下方添加 with jar,以便在 uberjar 中获取 java/main/resources 中的文件。 - gladiator
这对我有用!没有排除部分,SecurityException 一直困扰着我,但是现在它运作正常了! - techcraver
1
最好使用sourceSets.getByName('main').runtimeClasspath - mkobit
有人知道这在 Kotlin 中会是什么样子(针对 build.gradle.kts 文件)吗? - user64141

37

谢谢你的指针。它很有用。虽然我又遇到了一个问题,但通过一些谷歌搜索解决了。我会添加另一个答案来扩展它。 - missingfaktor
看起来这个食谱现在需要登录。由于这正是我正在寻找的,你能把配方粘贴在这里吗? - oarsome
1
@tarzan 三年后,我现在会使用阴影插件 https://github.com/johnrengelman/shadow。 - tim_yates
这非常简单,第一次就成功了(在尝试了许多其他“答案”之后:https://dev59.com/O2Ag5IYBdhLWcg3wU5gS)。 - Hugo Zaragoza
三年时间里发生的变化很多,但我仍会使用阴影插件;-) - tim_yates
shadowjar并没有得到很好的维护。请参见https://github.com/johnrengelman/shadow/issues/476以及其他关键问题,这些问题已经数月未得到解决。 - Gili

8
只需将以下内容添加到您的Java模块的build.gradle文件中即可:
mainClassName = "my.main.Class"
jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  

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

这将导致[module_name]/build/libs/[module_name].jar文件的生成。

但那段代码是什么意思呢?configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } 这段代码是做什么的? - Sam Redway
1
@SamRedway configurations.compile.collect 会从 compile 收集一些东西。三元运算符允许它将文件夹和 zip 文件(如 jars)一起拉入,就像它们也是文件夹一样。 - pal
我还没有尝试过这里发布的其他版本,但这个版本运行良好,而且简单易懂。 - chris
此答案不包括任何已声明为 runtimeruntimeOnly 的依赖项,这些依赖项会导致应用程序在运行时崩溃。 - mkobit
1
@mkobit 您可以按照此答案中的说明,将compile替换为runtimeClasspath - Franklin Yu

5

我发现这个项目非常有用。参考它,我的Gradle uberjar任务将是:

task uberjar(type: Jar, dependsOn: [':compileJava', ':processResources']) {
    from files(sourceSets.main.output.classesDir)
    from configurations.runtime.asFileTree.files.collect { zipTree(it) }

    manifest {
        attributes 'Main-Class': 'SomeClass'
    }
}

当我尝试这个操作时,我收到了“Manifest主属性的无效签名文件摘要”的错误提示。 - Nicholas DiPiazza
你需要像missingfaktor的答案一样,排除掉以下内容: exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" - Nicholas DiPiazza
似乎无法与Gradle 5.3.1一起使用:“无法获取类型为org.gradle.api.internal.tasks.DefaultSourceSetOutput的主类的未知属性'classesDir'。” - lathspell
它给了我java.lang.UnsupportedOperationException。 - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

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