使用Gradle构建具有依赖关系的jar

Ben*_*ann 108 uberjar gradle

我有一个多项目构建,我在一个子项目中设置了一个任务来构建一个胖罐.我创建的任务类似于食谱中描述的任务.

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

运行它会导致以下错误:

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

我不确定这个错误意味着什么.我还在Gradle JIRA上报告了这个问题,以防它出现问题.

Ben*_*ann 163

我在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) }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我必须为我的项目修改它到configurations.runtime.collect,因为我也有运行时依赖项. (4认同)
  • 我必须添加 `def mainClassName` 才能使代码工作......我收到了无法为根项目设置未知属性 'mainClassName' (3认同)
  • 你如何处理文件名冲突?不同 JAR 中相同路径上的文件将被覆盖。 (2认同)
  • 不幸的是,这不再起作用。我使用gradle 4.10和新的“实现”配置,而不是现在不建议使用的“编译”。上面的代码为我构建了一个没有依赖项的小罐子。当我更改它时(`from {configuration.implementation.collect {...}}`),发生错误,提示不允许直接解决配置“ implementation” (2认同)
  • @BastianVoigt `configurations.compileClasspath` 将修复所有 `implementation`,但会忽略 `api` 依赖项 afik。在另一个答案中找到解决方案“runtimeClasspath”。这也包括“api”依赖项。 (2认同)

Fel*_*lix 62

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

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

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

  • 这不起作用.使用此解决方案,清单文件为空. (5认同)
  • 我的2美分:设置分类器比更改名称更好.将classifier ='all'而不是baseName = project.name +'-all'.这样您就可以使工件名称符合Maven/Nexus策略. (4认同)
  • 我找不到关于`with jar` 关键字的任何类型的文档,它到底是做什么的? (2认同)

blo*_*ets 56

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

  1. 使用Gradle 1.5时,在fatJar任务中无法识别清单标记,因此无法直接设置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
}
Run Code Online (Sandbox Code Playgroud)

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

artifacts {
    archives fatJar
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这也修复了我的一个依赖罐签署时遇到的问题.签名文件被放入我的jar的META-INF中,但签名不再与内容相匹配. (3认同)
  • 特别感谢`artifacts`:正是我正在寻找的。 (2认同)

Lan*_*abs 24

由于现在不推荐使用编译来列出依赖项,并且所有依赖项都应该切换到实现,因此构建具有所有依赖项的 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)
Run Code Online (Sandbox Code Playgroud)

这是完整的 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) }
}}
Run Code Online (Sandbox Code Playgroud)


Aro*_*nte 8

这对我来说很好.

我的主要课程:

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");
    }

}
Run Code Online (Sandbox Code Playgroud)

它是我的文件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
}
Run Code Online (Sandbox Code Playgroud)

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

java -jar ProyectoEclipseTest-all.jar
Run Code Online (Sandbox Code Playgroud)

输出很棒:

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
Run Code Online (Sandbox Code Playgroud)


小智 8

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

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

  To build this archive, please enable the zip64 extension.
Run Code Online (Sandbox Code Playgroud)

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

mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  
  zip64 = true
  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  }
}
Run Code Online (Sandbox Code Playgroud)


Sal*_*ngo 7

根据 @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"
  }
}
Run Code Online (Sandbox Code Playgroud)


Ita*_*tto 6

要使用主可执行类生成胖JAR,避免签名JAR的问题,我建议使用gradle-one-jar插件.一个使用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'
}
Run Code Online (Sandbox Code Playgroud)


小智 5

简单的溶液

jar {
    manifest {
        attributes 'Main-Class': 'cova2.Main'
    } 
    doFirst {
        from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}
Run Code Online (Sandbox Code Playgroud)