web-dev-qa-db-fra.com

Utiliser Gradle pour construire un bocal avec des dépendances

J'ai construit un multiprojet et je me suis chargé de construire un gros pot dans l'un des sous-projets. J'ai créé la tâche similaire à celle décrite dans le livre de recettes .

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

Son exécution entraîne l'erreur suivante:

Cause: Vous ne pouvez pas modifier une configuration qui n'est pas à l'état non résolu!

Je ne suis pas sûr de ce que cette erreur signifie. J'ai aussi signalé ceci sur le Gradle JIRA au cas où il s'agirait d'un bogue .

105
Ben McCann

J'ai posté ne solution dans JIRA contre 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) }
  }
}

Notez que mainClassName doit apparaître AVANT jar {.

160
Ben McCann

Si vous souhaitez que la tâche jar se comporte normalement et qu'une tâche additionnelle fatJar, utilisez les éléments suivants:

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

La partie importante est with jar. Sans cela, les classes de ce projet ne sont pas incluses.

61
Felix

La réponse de @felix m'a presque amené là-bas. J'ai eu deux problèmes:

  1. Avec Gradle 1.5, la balise manifeste n’était pas reconnue dans la tâche fatJar et l’attribut Main-Class ne pouvait donc pas être défini directement.
  2. le pot contenait des fichiers META-INF externes en conflit.

La configuration suivante résout ce problème

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
}

Pour ajouter ceci à la tâche standard d'assemblage ou de construction, ajoutez:

artifacts {
    archives fatJar
}

Edit: merci à @mjaggard: dans les versions récentes de Gradle, changez configurations.runtime à configurations.runtimeClasspath

55
blootsvoets

Cela fonctionne bien pour moi.

Ma classe principale:

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

}

Et c’est le contenu de mon fichier 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
}

Et j'écris ce qui suit dans ma console:

Java -jar ProyectoEclipseTest-all.jar

Et le résultat est excellent:

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
8

Pour générer un gros JAR avec une classe exécutable principale, en évitant les problèmes de JAR signés, je suggère plugin gradle-one-jar . Un simple plugin qui utilise le projet One-JAR .

Facile à utiliser:

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
Italo Borssatto

Sulution simple

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

La réponse de @ben fonctionne presque pour moi sauf que mes dépendances sont trop grandes et que j'ai l'erreur suivante

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

  To build this archive, please enable the Zip64 extension.

Pour résoudre ce problème, je dois utiliser le code suivant

mainClassName = "com.company.application.Main"

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