使用Gradle构建具有依赖项的jar


122

我有一个多项目构建,我将一个任务放在一个子项目中来构建胖子。我创建了与食谱中描述的任务相似的任务。

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

运行它会导致以下错误:

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

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

Answers:


195

更新:在较新的Gradle版本(4+)中,compile不推荐使用限定符,而推荐使用new apiimplementation配置。如果使用这些,则以下内容将为您工作:

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

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

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

对于较早的gradle版本,或者如果您仍对依赖项使用“ compile”限定符,则此方法应该有效:

// 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 {


4
我必须将其修改为我的项目的configurations.runtime.collect,因为我也具有运行时依赖项。
vextorspace,2016年

2
我必须添加def mainClassName才能使代码正常工作...我收到的消息无法为根项目设置未知属性“ mainClassName”
hanskoff

1
如何处理文件名冲突?不同JAR文件中同一路径上的文件将被覆盖。
WST

3
不幸的是,这不再起作用。我使用gradle 4.10和新implementation配置,而不是现在已弃用的compile。上面的代码为我构建了一个没有依赖关系的小罐子。当我更改它(from { configurations.implementation.collect {...} })时,发生错误,提示不允许直接解决配置“实现”
Bastian Voigt

1
@BastianVoigt configurations.compileClasspath将修复所有implementations,但将忽略api依赖项。在这里找到另一个答案的解决方案runtimeClasspath。这也包括api依赖性。
休息

64

@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
}

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

artifacts {
    archives fatJar
}

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


3
这也解决了我的一个依赖罐签名的问题。签名文件已放入我的jar的META-INF中,但签名不再与内容匹配。
Flavin

2
特别感谢artifacts:正是我想要的。
AlexR

运行运行gradle fatJar时依赖项时,似乎未对其进行编译,因此无法复制它们。
mjaggard

64

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

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

重要的是with jar。没有它,该项目的类别将不包括在内。


1
另请参见下面的问题,如果你正在使用签名的罐子包括和运行与签名一个问题:stackoverflow.com/questions/999489/...
彼得N.斯坦梅茨

6
这是行不通的。此解决方案的清单文件为空。
乔纳斯(Jonas)

4
我的2分钱:设置分类器比更改名称更好。将classifier ='all'代替baseName = project.name +'-all'。这样,您就可以使工件名称符合Maven / Nexus策略。
taciosd '16

1
加入group "build"这个任务将在build组(与其他任务,即jar任务。
MAGx2

1
我找不到关于该with jar关键字的任何文档,它的作用是什么?
Philipp Hemmelmayr

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

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'
}

5

简单的溶出

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

5

@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) }
  }
}

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


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()
}


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

-1

如果您习惯于使用蚂蚁,那么也可以使用Gradle尝试相同的操作:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.