153

我有一个多项目构建,并且我在其中一个子项目中放置了一个构建胖 jar 的任务。我创建了类似于食谱中描述的任务。

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

运行它会导致以下错误:

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

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

4

17 回答 17

239

我在 JIRA 中针对 Gradle发布了一个解决方案:

// Include dependent libraries in archive.
mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  

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

请注意,mainClassName必须出现 BEFORE jar {

于 2011-02-04T03:34:23.663 回答
75

@felix 的回答几乎把我带到了那里。我有两个问题:

  1. 在 Gradle 1.5 中,fatJar 任务内部无法识别 manifest 标签,因此无法直接设置 Main-Class 属性
  2. jar 有冲突的外部 META-INF 文件。

以下设置解决了这个问题

jar {
  manifest {
    attributes(
      'Main-Class': 'my.project.main',
    )
  }
}

task fatJar(type: Jar) {
  manifest.from jar.manifest
  classifier = 'all'
  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  } {
    exclude "META-INF/*.SF"
    exclude "META-INF/*.DSA"
    exclude "META-INF/*.RSA"
  }
  with jar
}

要将其添加到标准组装或构建任务,请添加:

artifacts {
    archives fatJar
}

编辑:感谢@mjaggard:在最新版本的 Gradle 中,更改configurations.runtimeconfigurations.runtimeClasspath

于 2015-07-15T09:22:55.593 回答
64

如果您希望jar任务正常运行并且还有其他fatJar任务,请使用以下命令:

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

重要的部分是with jar。没有它,这个项目的类不包括在内。

于 2014-03-25T16:33:55.890 回答
11

由于现在不推荐使用compile来列出依赖项,并且所有人都应该切换到实现,因此构建具有所有依赖项的 Jar 的解决方案应该使用该网站中的示例。

https://docs.gradle.org/current/userguide/working_with_files.html#sec:creating_uber_jar_example

特别是这个命令:

configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it)

这是完整的 gradle 部分: [1]:https ://docs.gradle.org/current/userguide/working_with_files.html#sec:creating_uber_jar_example

task uberJar(type: Jar) {
archiveClassifier = 'uber'

from sourceSets.main.output

dependsOn configurations.runtimeClasspath
from {
    configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}}
于 2021-04-01T19:57:35.873 回答
9

这对我来说很好。

我的主要课程:

package com.curso.online.gradle;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

public class Main {

    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class);
        logger.debug("Starting demo");

        String s = "Some Value";

        if (!StringUtils.isEmpty(s)) {
            System.out.println("Welcome ");
        }

        logger.debug("End of demo");
    }

}

这是我的文件 build.gradle 的内容:

apply plugin: 'java'

apply plugin: 'eclipse'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
    compile  'org.apache.commons:commons-lang3:3.0'
    compile  'log4j:log4j:1.2.16'
}

task fatJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'com.curso.online.gradle.Main'
    }
    baseName = project.name + '-all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

我在控制台中写了以下内容:

java -jar ProyectoEclipseTest-all.jar

输出很棒:

log4j:WARN No appenders could be found for logger (com.curso.online.gradle.Main)
.
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more in
fo.
Welcome
于 2014-08-10T19:42:00.960 回答
8

@ben 的答案几乎对我有用,除了我的依赖项太大并且出现以下错误

Execution failed for task ':jar'.
> archive contains more than 65535 entries.

  To build this archive, please enable the zip64 extension.

要解决此问题,我必须使用以下代码

mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  
  zip64 = true
  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  }
}
于 2018-03-15T22:45:09.863 回答
6

要生成带有主要可执行类的胖 JAR,避免签名 JAR 出现问题,我建议使用 gradle-one-jar plugin。一个使用One-JAR 项目的简单插件。

便于使用:

apply plugin: 'gradle-one-jar'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.rholder:gradle-one-jar:1.0.4'
    }
}

task myjar(type: OneJar) {
    mainClass = 'com.benmccann.gradle.test.WebServer'
}
于 2015-10-29T17:08:23.723 回答
5

简单的解决方案

jar {
    manifest {
        attributes 'Main-Class': 'cova2.Main'
    } 
    doFirst {
        from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}
于 2015-02-09T21:26:46.637 回答
3

根据@blootsvoets 提出的解决方案,我以这种方式编辑了我的 jar 目标:

jar {
    manifest {
        attributes('Main-Class': 'eu.tib.sre.Main')
    }
    // Include the classpath from the dependencies 
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    // This help solve the issue with jar lunch
    {
    exclude "META-INF/*.SF"
    exclude "META-INF/*.DSA"
    exclude "META-INF/*.RSA"
  }
}
于 2021-01-29T09:36:17.927 回答
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.

于 2019-12-09T01:51:03.010 回答
1

排除不需要的 Manifest 条目修复了 Gradle 构建 jar 文件中未找到 MainClass 文件的错误。

jar{
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
    from {
      -----
    }
}
于 2021-01-06T20:39:49.537 回答
0

shadowJar我通过插件使用任务. com.github.jengelman.gradle.plugins:shadow:5.2.0

使用刚刚运行的./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()
}

于 2020-01-24T09:04:51.470 回答
0

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

plugins {
    id 'java-library'
}

jar {
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}
于 2020-06-24T10:21:01.147 回答
0

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

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

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

于 2021-07-22T17:28:05.977 回答
0

有无缝设置的 gradle plugin shadow jar。

plugins {
    id "com.github.johnrengelman.shadow" version "5.0.0"
}

shadowJar {
    mergeServiceFiles()
}

请在此处检查与您的 gradle 版本的版本兼容性: https ://github.com/johnrengelman/shadow#latest-test-compatibility

于 2021-12-01T12:46:25.447 回答
0

如果“编译”和“实现”不起作用,请尝试“runtimeClasspath”。

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

    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}
于 2022-01-18T15:48:33.777 回答
-1

如果您习惯了 ant,那么您也可以尝试使用 Gradle:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}
于 2015-04-28T12:58:21.683 回答