Usar Gradle para construir un jar con dependencias


Tengo una compilación multiproyecto y puse una tarea para construir un bote de grasa en uno de los subproyectos. Creé la tarea similar a la descrita en el libro de cocina.

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

Al ejecutarlo se produce el siguiente error:

Causa: No se puede cambiar una configuración que no está en estado sin resolver!

No estoy seguro de lo que significa este error. También informé de esto en Gradle JIRA en caso de que sea un error.

Author: Yves M., 2011-02-02

8 answers

He publicado una solución en JIRA contra 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) }
  }
}
 146
Author: Ben McCann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-11 22:55:05

Si desea que la tarea jar se comporte normalmente y una tarea additinal fatJar, use lo siguiente:

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

La parte importante es with jar. Sin ella, las clases de este proyecto no están incluidas.

 56
Author: Felix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-23 12:22:07

La respuesta de @felix casi me llevó allí. Tuve dos problemas:

  1. Con Gradle 1.5, la etiqueta manifest no se reconocía dentro de la tarea fatJar, por lo que el atributo Main-Class no se podía establecer directamente
  2. el jar tenía archivos META-INF externos conflictivos.

La siguiente configuración resuelve esto

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
}

Para agregar esto a la tarea estándar de ensamblar o construir, agregue:

artifacts {
    archives fatJar
}

Editar: gracias a @mjaggard: en versiones recientes de Gradle, cambiar configurations.runtime to configurations.runtimeClasspath

 41
Author: blootsvoets,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-11 14:07:19

Esto funciona bien para mí.

Mi clase principal:

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

}

Y es el contenido de mi compilación de archivos.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
}

Y escribo lo siguiente en mi consola:

java -jar ProyectoEclipseTest-all.jar

Y la salida es grande:

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
Author: Aron Elias Herrera Ponte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-19 18:52:59

Para generar un fat JAR con una clase ejecutable principal, evitando problemas con JARs firmados, sugiero el complemento gradle-one-jar. Un plugin simple que utiliza el proyecto One-JAR.

Fácil de usar:

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
Author: Italo Borssatto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-29 17:08:23

Sulution simple

jar {
    manifest {
        attributes 'Main-Class': 'cova2.Main'
    } 
    doFirst {
        from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}
 2
Author: Jonas Mayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-09 21:26:46

La respuesta de @ben casi funciona para mí, excepto que mis dependencias son demasiado grandes y obtuve el siguiente error

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

  To build this archive, please enable the zip64 extension.

Para solucionar este problema, tengo que usar el siguiente código

mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  
  zip64 = true
  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  }
}
 1
Author: Algorithm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-15 22:45:09

Si estás acostumbrado a ant, entonces podrías intentar lo mismo con Gradle también:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}
 -1
Author: mig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 13:31:42