Bağımlılıkları olan bir jar oluşturmak için Gradle'ı kullanma


122

Çok projeli bir yapım var ve alt projelerden birinde şişman bir kavanoz inşa etmek için bir görev verdim. Yemek kitabında anlatılana benzer bir görev yarattım .

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

Çalıştırmak aşağıdaki hataya neden olur:

Neden: Çözümlenmemiş durumda olmayan bir konfigürasyonu değiştiremezsiniz!

Bu hatanın ne anlama geldiğinden emin değilim. Ayrıca bir hata olması durumunda bunu Gradle JIRA'da da rapor ettim .

Yanıtlar:


196

Güncelleme: Daha yeni Gradle sürümlerinde (4+) compileniteleyici, yeni apive implementationyapılandırmalar lehine kullanımdan kaldırılmıştır . Bunları kullanırsanız, aşağıdakiler sizin için çalışmalıdır:

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

Daha eski gradle sürümleri için veya bağımlılıklarınız için hala "derleme" niteleyicisini kullanıyorsanız, bu çalışmalıdır:

// 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ÖNCE görünmesi gerektiğini unutmayın jar {.


4
Çalışma zamanı bağımlılıklarım olduğu için projem için bunu configuration.runtime.collect olarak değiştirmek zorunda kaldım.
vextorspace

2
def mainClassNameKodun çalışması için eklemem gerekiyordu ... alıyordum Kök proje için bilinmeyen 'mainClassName' özelliği ayarlanamadı
hanskoff

1
Dosya adı çakışmalarıyla nasıl başa çıkarsınız? Farklı JAR'larda aynı yol üzerindeki dosyaların üzerine yazılacaktır.
wst

3
Maalesef bu artık çalışmıyor. Artık kullanımdan implementationkaldırılan yerine 4.10 sınıfı ve yeni yapılandırmayı kullanıyorum compile. Yukarıdaki kod bana bağımlılıklar olmadan küçük bir kavanoz oluşturuyor. Değiştirdiğimde ( from { configurations.implementation.collect {...} }), konfigürasyonun çözümlenmesine doğrudan izin verilmediğini söyleyen bir hata
Bastian Voigt

1
@BastianVoigt configurations.compileClasspathtüm s'leri düzeltir implementation, ancak apibağımlılıkları dışarıda bırakır afik. Burada başka bir cevapta çözüm bulundu runtimeClasspath. Bu apibağımlılıkları da içerir .
48'de yeniden

64

@Felix'in cevabı beni neredeyse oraya getirdi. İki sorunum vardı:

  1. Gradle 1.5 ile, manifest etiketi fatJar görevinde tanınmıyordu, bu nedenle Main-Class niteliği doğrudan ayarlanamıyordu.
  2. kavanozda çakışan harici META-INF dosyaları var.

Aşağıdaki kurulum bunu çözer

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
}

Bunu standart birleştirme veya inşa görevine eklemek için şunları ekleyin:

artifacts {
    archives fatJar
}

Düzenleme: @mjaggard sayesinde: Gradle son sürümlerinde, değişim configurations.runtimeiçinconfigurations.runtimeClasspath


3
Bu aynı zamanda bağımlılık kavanozlarımdan birinin imzalandığı bir sorunu da çözdü. İmza dosyaları kavanozumun META-INF'ine konuldu, ancak imza artık içerikle eşleşmiyor.
Flavin

2
Özel teşekkürler artifacts: tam olarak aradığım şey.
AlexR

Çalıştırma gradle fatJarzamanı bağımlılıkları derlenmiş gibi görünmüyor, bu yüzden kopyalanamazlar.
mjaggard

64

jarGörevin normal davranmasını ve ayrıca ek bir fatJargörevin olmasını istiyorsanız , aşağıdakileri kullanın:

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

Önemli olan kısım with jar. Onsuz, bu projenin sınıfları dahil edilmez.


1
İmzaları dahil etmek ve imzalarla ilgili bir sorunla karşılaşmak için imzalı kavanozlar kullanıyorsanız şu soruna da bakın: stackoverflow.com/questions/999489/…
Peter N. Steinmetz

6
Bu çalışmıyor. Manifest dosyası bu çözümle boştur.
Jonas

4
Benim 2 sentim: Adı değiştirmektense bir sınıflandırıcı ayarlamak daha iyidir. BaseName = proje.name + '-all' yerine sınıflandırıcı = 'tümü' koyun. Bu şekilde yapı adını Maven / Nexus politikalarına uygun tutarsınız.
taciosd

1
Ekle group "build"ve bu görev buildgrupta olacak (diğer görevlerle, yani jargörev.
MAGx2

1
with jarAnahtar kelimeyle ilgili herhangi bir belge bulamıyorum , tam olarak ne işe yarar?
Philipp Hemmelmayr

9

Bu benim için iyi çalışıyor.

Ana sınıfım:

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

}

Ve build.gradle dosyamın içeriğidir:

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
}

Ve konsoluma şunu yazıyorum:

java -jar ProyectoEclipseTest-all.jar

Ve çıktı harika:

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

İmzalı JAR'larla ilgili sorunlardan kaçınarak ana çalıştırılabilir bir sınıfla dolu bir JAR oluşturmak için gradle-one-jar eklentisini öneririm . One-JAR projesini kullanan basit bir eklenti .

Kullanımı kolay:

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

Basit sulandırma

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

5

@ Benin cevabı, bağımlılıklarımın çok büyük olması ve aşağıdaki hatayı almam dışında neredeyse benim için çalışıyor

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

  To build this archive, please enable the zip64 extension.

Bu sorunu çözmek için aşağıdaki kodu kullanmam gerekiyor

mainClassName = "com.company.application.Main"

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

1

Projeden birden fazla kavanoz inşa etmesi gerekenler için.

Gradle'da bir işlev oluşturun:

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

sonra ara:

task makeMyJar(type: Jar) {
    jarFactory(it, 'MyJar', 'org.company.MainClass')
}

5. sınıfta çalışıyor.

Kavanoz yerleştirilecek ./build/libs.


0

shadowJarEklentiye göre görev kullanıyorum. com.github.jengelman.gradle.plugins:shadow:5.2.0

Kullanım sadece çalıştırma ./gradlew app::shadowJar sonuç dosyası şu adreste olacaktır:MyProject/app/build/libs/shadow.jar

üst düzey build.gradledosya:

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

uygulama modülü düzeyinde build.gradledosya

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 kitaplığı. "Jar görevi" ndeki kod, " gradle build " görevini çalıştırırken bağımlılıkları "build / libs / xyz.jar" a ekler .

plugins {
    id 'java-library'
}

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

-1

Karıncaya alışkınsanız, aynı şeyi Gradle ile de deneyebilirsiniz:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.