Compilando una Biblioteca
⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.
Empaquetado JAR
JAR
Un archivo JAR (Java Archive) es un formato de paquete que agrupa múltiples archivos de clase Java, metadatos y recursos (como textos, imágenes, etc.) en un único archivo para facilitar su distribución y despliegue. Los archivos JAR se basan en el formato ZIP y tienen una estructura similar.
En Gradle, la tarea jar
es responsable de empaquetar los archivos de clase y recursos de un proyecto en un archivo JAR. Esta tarea se ejecuta automáticamente cuando se ejecuta la tarea build
, y genera el archivo JAR dentro del directorio build/libs/
del proyecto.
A continuación, veremos cómo automatizar el proceso de empaquetado de la biblioteca y su uso en la aplicación:
- Empaquetar la biblioteca
lib
en un archivo JAR: Utilizaremos la tareajar
para generar el archivo JAR de la biblioteca. - Copiar el archivo JAR al módulo
app
: Configuraremos una tarea que copie automáticamente el JAR generado en el directoriolibs
del móduloapp
. - Configurar el módulo
app
para utilizar la biblioteca empaquetada: Actualizaremos las dependencias del móduloapp
para que utilice la biblioteca empaquetada en lugar de acceder a ella directamente.
Aunque podríamos realizar este proceso manualmente, aprovecharemos las capacidades de automatización de Gradle para hacerlo de manera eficiente y siguiendo las buenas prácticas.
Empaquetando la Biblioteca
El primer paso para automatizar el empaquetado de la biblioteca será crear un plugin de convenciones. Para ello, crearemos un nuevo archivo en convention-plugins/src/main/kotlin/compile.conventions.gradle.kts
.
En este archivo, definiremos una tarea personalizada que copie los archivos JAR del directorio build/libs
al directorio libs
del módulo app
. Como vimos en la lección sobre tareas personalizadas, comenzaremos con una tarea básica y luego la mejoraremos.
- Gradle Kotlin DSL
- Gradle Groovy DSL
tasks.register<Copy>("copyLib") {
group = "build"
description = "Copia la biblioteca al directorio de la aplicación"
from("build/libs")
into("$rootDir/app/libs")
doLast {
println("Biblioteca copiada al directorio app/libs")
}
}
Aquí pondía mi implementación en Groovy, si la tuviera.
Y ahora aplicamos este plugin en el archivo lib/build.gradle.kts
:
plugins {
id("compile.conventions")
}
// ...
Automatizando la Tarea
Ya que hemos definido la tarea copyLib
, podemos hacer que esta se ejecute automáticamente antes de la tarea compileKotlin
en el módulo de la aplicación. Esto garantiza que, cada vez que se compile la biblioteca, también se copie el archivo JAR al módulo app
.
- Gradle Kotlin DSL
- Gradle Groovy DSL
// ...
tasks.named("compileKotlin") {
dependsOn(":lib:copyLib")
}
En un futuro cercano, aquí pondría mi implementación en Groovy.
Ejecutando la Tarea
Cuando ejecutes la tarea build
en el proyecto, se ejecutará primero la tarea compileKotlin
, seguida de copyLib
, que copiará el archivo JAR al directorio libs
del módulo app
.
- Enunciado
- Solución
Ejecuta la tarea build
y verifica si el archivo JAR de la biblioteca se copia correctamente al módulo app
. Esto generará un error, ¿puedes identificar la causa?
El error será algo como esto:
> Task :app:compileKotlin FAILED
e: file:///.../gradle-basics/app/src/main/kotlin/cl/ravenhill/EchoApp.kt:5:17 Unresolved reference 'echo'.
FAILURE: Build failed with an exception.
Esto ocurre porque copiamos el archivo JAR, pero no configuramos el módulo app
para utilizarlo como una dependencia.
Configurando la Dependencia
Para que el módulo app
pueda utilizar la biblioteca empaquetada, actualizaremos las dependencias. Es similar a agregar una dependencia de una biblioteca externa, pero utilizaremos el archivo JAR local en lugar de un repositorio remoto.
- Gradle Kotlin DSL
- Gradle Groovy DSL
// ...
dependencies {
implementation(
fileTree("libs") {
include("lib-1.0.0.jar")
// include("...") // Agregar más bibliotecas si es necesario
}
)
}
Cuenta la leyenda que aquí pondría mi implementación en Groovy.
Si ejecutas la tarea build
todo debería funcionar, pero no lo hace debido a un error.
- Enunciado
- Solución
Ejecuta la tarea build
y analiza el error. ¿Puedes identificar la causa? ¿Cómo lo solucionarías?
El error debería ser similar a:
> Task :lib:jar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
A problem was found with the configuration of task ':lib:jar' (type 'Jar').
- Gradle detected a problem with the following location: 'E:/Documentos/.../lib-1.0.0.jar'.
Reason: Task ':lib:copyLib' uses this output of task ':lib:jar' without declaring an explicit dependency.
El problema es que copyLib
se ejecuta antes de que jar
haya generado el archivo JAR. Para corregirlo, copyLib
debe depender explícitamente de jar
.
Solución al error ¡No abrir si quieres resolverlo por tu cuenta!
El problema surge porque copyLib
necesita que jar
termine antes de ejecutarse. Gradle nos avisa que debemos hacer explícita la dependencia entre estas tareas.
- Gradle Kotlin DSL
- Gradle Groovy DSL
// ...
tasks.named("copyLib") {
dependsOn("jar")
}
Inserte implementación en Groovy aquí.
Aplicando esta corrección, al ejecutar la tarea build
, la biblioteca se empaquetará y copiará correctamente al módulo app
, que podrá utilizarla como una dependencia local.
Ahora podemos probar la aplicación y verificar que funcione correctamente con la biblioteca empaquetada.
./gradlew :app:run --args="Hello, Gradle!"
Pero esto no va a funcionar, ¿puedes identificar la causa? En la siguiente lección, veremos cómo solucionar este problema y asegurarnos de que la aplicación pueda acceder a la biblioteca empaquetada.
¿Con qué nos vamos?
Al completar este proceso, hemos aprendido cómo empaquetar una biblioteca en un archivo JAR utilizando Gradle y cómo automatizar la copia de ese JAR al módulo de nuestra aplicación. También vimos cómo configurar el módulo app
para que utilice el JAR empaquetado como una dependencia local.
Resumen de lo aprendido:
- Empaquetado JAR: Usamos la tarea
jar
para crear un archivo JAR con las clases y recursos del proyecto. - Tarea personalizada
copyLib
: Definimos una tarea para copiar el JAR generado al directoriolibs
del móduloapp
. - Configuración de dependencias: Configuramos el archivo
build.gradle
deapp
para que reconozca y use el archivo JAR copiado como una dependencia. - Solución de errores: Identificamos y corregimos un error de dependencia entre tareas, asegurando que la tarea
copyLib
se ejecute después de que la tareajar
haya generado el archivo JAR.
Con esta base, ahora puedes automatizar aún más tu flujo de trabajo y aplicar estas técnicas para proyectos más complejos y modulares.
Bibliografías Recomendadas
- 📚 "5. Dependency Management". (2014). Muschko, Benjamin and Dockter, Hans, en Gradle in Action, (pp. 105-132.) Manning.
- 🌐 "Local JAR Files as Gradle Dependencies." Accedido: 11 de septiembre de 2024. [En línea]. Disponible en: https://www.baeldung.com/gradle-dependencies-local-jar/
- 🌐 "JAR File Overview." Accedido: 11 de septiembre de 2024. [En línea]. Disponible en: https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jarGuide.html