Creando un fat jar con maven y gradle

Es muy común que necesitemos desarrollar una aplicación en Java cuyo ejecutable es un jar. A la vez, es muy frecuente que estemos usando librería de terceros que necesitamos tener junto a nuestro ejecutable para que la aplicación funcione correctamente. Una solución para evitar tener una gran cantidad de archivos jar, es crear un fat o uber jar.

Basicamente, un fat jar o uber jar, es un archivo auto-suficiente que contiene las clases y dependencies que se necesitan para correr una aplicación. En otras palabras, un único jar que contiene todos las librerias que necesita nuestra aplicación. De esta manera solamente tenemos que compartir un único jar sin importar si utilizamos librerías de terceros.

Este enfoque es muy útil para aplicaciones de escritorio y también para micro-servicios en Java.

Maven

Con maven podemos lograr esto utilizando el plugin maven-shade-plugin y a la fase package agregamos el goal shade. De manera opcional, podemos indicar con este plugin el main class que se ejecutara al iniciar nuestra aplicación.

<project>
    <dependencies>
         ...
    </dependencies>
	<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.orthanc.mypackage.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Gradle

Con gradle es aún más sencillo, solamente tenemos que usar el plugin jar incluido con la herramienta. De manera opcional también podemos indicar el main-class que deseamos usar en nuestra aplicación.

dependencies {
  //my dependencies
}

jar {
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
    manifest {
        attributes "Main-Class": "com.orthanc.mypackage.Main"
    }
}

Hay algunos fragmentos de codigo en internet y StackOverflow usando configurations.compile.collect . Sin embargo, no funcionan correctamente con dependencias transitivas o the modulos cuando estas son agregadas usando los scopes implementation o api en lugar de compile. Gradle 6 ha marcado el scope compile como deprecado y Gradle 7 ya no le da soporte.

Por lo tanto usar configurations.runtimeClasspath.collect es una mejor alternativa que incluye las dependencias transitivas y de modulos.

Referencias

Leave a Reply

Your email address will not be published. Required fields are marked *