Semana 13: Gestores de Dependencias en Java con VS Code
Introducción
Los gestores de dependencias son herramientas fundamentales en el desarrollo de Java que nos permiten:
- Gestionar librerías externas de forma automática
- Resolver conflictos entre versiones de dependencias
- Automatizar la construcción del proyecto
- Mantener la consistencia entre diferentes entornos de desarrollo
En esta semana exploraremos los dos gestores más populares: Maven y Gradle, utilizando las extensiones de Visual Studio Code.
Extensiones de VS Code para Java
Extension Pack for Java
La extensión principal que necesitamos es Extension Pack for Java, que incluye:
- Language Support for Java™ by Red Hat
- Debugger for Java
- Test Runner for Java
- Maven for Java
- Project Manager for Java
- Visual Studio IntelliCode
Extensiones Adicionales Recomendadas
- Gradle for Java: Soporte específico para proyectos Gradle
- Spring Boot Extension Pack: Para proyectos Spring Boot
- Lombok Annotations Support for VS Code: Soporte mejorado para Lombok
Maven: Gestión de Dependencias
Estructura de un Proyecto Maven
mi-proyecto-maven/
├── pom.xml
├── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── ejemplo/
│ │ └── App.java
│ └── test/
│ └── java/
│ └── com/
│ └── ejemplo/
│ └── AppTest.java
└── target/
Configuración del archivo pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Información del proyecto -->
<groupId>com.ejemplo</groupId>
<artifactId>mi-proyecto-maven</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Mi Proyecto Maven</name>
<description>Ejemplo de proyecto Maven con Lombok</description>
<!-- Propiedades del proyecto -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.30</lombok.version>
</properties>
<!-- Dependencias -->
<dependencies>
<!-- Lombok para reducir código boilerplate -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- Configuración de plugins -->
<build>
<plugins>
<!-- Plugin del compilador -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Uso de Maven en VS Code
- Crear proyecto: Usar Command Palette (
Ctrl+Shift+P) → "Java: Create Java Project" → "Maven" - Gestión de dependencias:
- Editar
pom.xml - VS Code detecta automáticamente los cambios
- Usar "Java: Reload Projects" si es necesario
- Comandos Maven: Disponibles en la paleta de comandos con prefijo "Maven:"
Ejemplo Práctico con Maven y Lombok
Clase de Ejemplo con Lombok (Maven)
package com.ejemplo.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
/**
* Clase que representa un Usuario del sistema
* Utiliza Lombok para reducir código boilerplate
* Configurado para proyecto Maven
*/
@Data // Genera getters, setters, toString, equals y hashCode
@NoArgsConstructor // Genera constructor sin parámetros
@AllArgsConstructor // Genera constructor con todos los parámetros
@Builder // Genera patrón Builder
public class Usuario {
private Long id;
private String nombre;
private String email;
private LocalDateTime fechaCreacion;
private List<String> roles;
private boolean activo;
/**
* Método personalizado que utiliza el logger de Lombok
*/
public void saludar() {
System.out.println("Hola, soy " + nombre + " con email " + email);
}
/**
* Método que demuestra el uso del builder
*/
public static Usuario crearUsuarioEjemplo() {
return Usuario.builder()
.nombre("Juan Pérez")
.email("juan.perez@ejemplo.com")
.fechaCreacion(LocalDateTime.now())
.roles(List.of("USER", "ADMIN"))
.activo(true)
.build();
}
}
Clase Principal de Ejemplo (Maven)
package com.ejemplo;
import com.ejemplo.model.Usuario;
import java.time.LocalDateTime;
import java.util.Arrays;
/**
* Clase principal que demuestra el uso de Lombok en Maven
*/
public class App {
public static void main(String[] args) {
System.out.println("Iniciando aplicación Maven con Lombok");
// Ejemplo 1: Usando constructor sin parámetros y setters
Usuario usuario1 = new Usuario();
usuario1.setNombre("María García");
usuario1.setEmail("maria.garcia@ejemplo.com");
usuario1.setFechaCreacion(LocalDateTime.now());
usuario1.setActivo(true);
System.out.println("Usuario 1 creado: " + usuario1);
// Ejemplo 2: Usando constructor con todos los parámetros
Usuario usuario2 = new Usuario(
2L,
"Carlos López",
"carlos.lopez@ejemplo.com",
LocalDateTime.now(),
Arrays.asList("USER"),
true
);
System.out.println("Usuario 2 creado: " + usuario2);
// Ejemplo 3: Usando el patrón Builder
Usuario usuario3 = Usuario.builder()
.id(3L)
.nombre("Ana Martínez")
.email("ana.martinez@ejemplo.com")
.fechaCreacion(LocalDateTime.now())
.roles(Arrays.asList("USER", "MODERATOR"))
.activo(true)
.build();
System.out.println("Usuario 3 creado con Builder: " + usuario3);
// Ejemplo 4: Usando método estático
Usuario usuario4 = Usuario.crearUsuarioEjemplo();
usuario4.saludar();
// Demostrando métodos generados automáticamente
demostrarMetodosLombok(usuario1, usuario2, usuario3, usuario4);
}
private static void demostrarMetodosLombok(Usuario... usuarios) {
System.out.println("=== Demostrando métodos generados por Lombok en Maven ===");
for (Usuario usuario : usuarios) {
// toString() generado automáticamente
System.out.println("toString(): " + usuario.toString());
// Getters generados automáticamente
System.out.println("Nombre: " + usuario.getNombre() +
", Email: " + usuario.getEmail() +
", Activo: " + usuario.isActivo());
}
// equals() y hashCode() generados automáticamente
Usuario usuarioCopia = new Usuario();
usuarioCopia.setNombre(usuarios[0].getNombre());
usuarioCopia.setEmail(usuarios[0].getEmail());
usuarioCopia.setFechaCreacion(usuarios[0].getFechaCreacion());
usuarioCopia.setActivo(usuarios[0].isActivo());
System.out.println("¿Son iguales usuario1 y usuarioCopia? " +
usuarios[0].equals(usuarioCopia));
}
}
Configuración de VS Code para Maven y Lombok
Configuración específica para Maven en settings.json
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic",
"java.saveActions.organizeImports": true,
"java.format.settings.url": "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml",
"lombok.enabled": true,
"maven.executable.path": "auto",
"maven.terminal.useJavaHome": true,
"maven.view": "hierarchical"
}
Configuración en launch.json para debugging con Maven
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch App (Maven)",
"request": "launch",
"mainClass": "com.ejemplo.App",
"projectName": "mi-proyecto-maven",
"vmArgs": "-javaagent:${userHome}/.m2/repository/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar"
}
]
}
Mejores Prácticas para Maven
- Usar propiedades para versiones de dependencias
- Definir encoding explícitamente
- Usar dependency management para proyectos multi-módulo
- Mantener pom.xml limpio y bien documentado
- Configurar annotation processors correctamente para Lombok
- Usar perfiles para diferentes entornos
Troubleshooting Maven
Problemas comunes con Maven y Lombok
- Lombok no funciona: Verificar que la extensión esté instalada y habilitada
- Errores de compilación: Asegurar que annotation processor esté configurado en el plugin del compilador
- Métodos no reconocidos: Recargar el proyecto Java con
Ctrl+Shift+P→ "Java: Reload Projects" - Dependencias no se descargan: Verificar conexión y repositorios en pom.xml
- Versión de Java incorrecta: Revisar propiedades del compilador
Gradle: Gestión de Dependencias
Estructura de un Proyecto Gradle
mi-proyecto-gradle/
├── build.gradle
├── settings.gradle
├── gradle/
│ └── wrapper/
├── gradlew
├── gradlew.bat
└── src/
├── main/
│ └── java/
│ └── com/
│ └── ejemplo/
│ └── App.java
└── test/
└── java/
└── com/
└── ejemplo/
└── AppTest.java
Configuración del archivo build.gradle
plugins {
id 'java'
id 'application'
}
// Información del proyecto
group = 'com.ejemplo'
version = '1.0.0'
description = 'Ejemplo de proyecto Gradle con Lombok'
// Configuración de Java
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
// Configuración de la aplicación
application {
mainClass = 'com.ejemplo.App'
}
// Repositorios donde buscar dependencias
repositories {
mavenCentral()
}
// Versiones de dependencias
ext {
lombokVersion = '1.18.30'
}
// Dependencias del proyecto
dependencies {
// Lombok para reducir código boilerplate
compileOnly "org.projectlombok:lombok:${lombokVersion}"
annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
// Dependencias para testing
testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
}
// Configuración de tareas
tasks.named('test') {
useJUnitPlatform()
}
// Configuración del compilador
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
options.compilerArgs += ['-parameters']
}
// Configuración para generar JAR ejecutable
jar {
manifest {
attributes(
'Main-Class': 'com.ejemplo.App'
)
}
}
Configuración del archivo settings.gradle
rootProject.name = 'mi-proyecto-gradle'
Uso de Gradle en VS Code
- Crear proyecto: Usar Command Palette → "Java: Create Java Project" → "Gradle"
- Gestión de dependencias:
- Editar
build.gradle - VS Code sincroniza automáticamente
- Usar "Java: Reload Projects" para forzar sincronización
- Comandos Gradle: Disponibles en la paleta de comandos con prefijo "Gradle:"
Ejemplo Práctico con Gradle y Lombok
Clase de Ejemplo con Lombok (Gradle)
package com.ejemplo.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Arrays;
/**
* Clase que representa un Usuario del sistema
* Utiliza Lombok para reducir código boilerplate
* Configurado para proyecto Gradle
*/
@Data // Genera getters, setters, toString, equals y hashCode
@NoArgsConstructor // Genera constructor sin parámetros
@AllArgsConstructor // Genera constructor con todos los parámetros
@Builder // Genera patrón Builder
public class Usuario {
private Long id;
private String nombre;
private String email;
private LocalDateTime fechaCreacion;
private List<String> roles;
private boolean activo;
/**
* Método personalizado que utiliza el logger de Lombok
*/
public void saludar() {
System.out.println("Hola, soy " + nombre + " con email " + email);
}
/**
* Método que demuestra el uso del builder
*/
public static Usuario crearUsuarioEjemplo() {
return Usuario.builder()
.nombre("Ana Rodríguez")
.email("ana.rodriguez@ejemplo.com")
.fechaCreacion(LocalDateTime.now())
.roles(List.of("USER", "DEVELOPER"))
.activo(true)
.build();
}
}
Clase Principal de Ejemplo (Gradle)
package com.ejemplo;
import com.ejemplo.model.Usuario;
import java.time.LocalDateTime;
import java.util.Arrays;
/**
* Clase principal que demuestra el uso de Lombok en Gradle
*/
public class App {
public static void main(String[] args) {
System.out.println("Iniciando aplicación Gradle con Lombok");
// Ejemplo 1: Usando constructor sin parámetros y setters
Usuario usuario1 = new Usuario();
usuario1.setNombre("Pedro Martín");
usuario1.setEmail("pedro.martin@ejemplo.com");
usuario1.setFechaCreacion(LocalDateTime.now());
usuario1.setActivo(true);
System.out.println("Usuario 1 creado: " + usuario1);
// Ejemplo 2: Usando constructor con todos los parámetros
Usuario usuario2 = new Usuario(
2L,
"Laura Sánchez",
"laura.sanchez@ejemplo.com",
LocalDateTime.now(),
Arrays.asList("USER", "TESTER"),
true
);
System.out.println("Usuario 2 creado: " + usuario2);
// Ejemplo 3: Usando el patrón Builder
Usuario usuario3 = Usuario.builder()
.id(3L)
.nombre("Miguel Torres")
.email("miguel.torres@ejemplo.com")
.fechaCreacion(LocalDateTime.now())
.roles(Arrays.asList("USER", "ARCHITECT"))
.activo(true)
.build();
System.out.println("Usuario 3 creado con Builder: " + usuario3);
// Ejemplo 4: Usando método estático
Usuario usuario4 = Usuario.crearUsuarioEjemplo();
usuario4.saludar();
// Demostrando métodos generados automáticamente
demostrarMetodosLombok(usuario1, usuario2, usuario3, usuario4);
}
private static void demostrarMetodosLombok(Usuario... usuarios) {
System.out.println("=== Demostrando métodos generados por Lombok en Gradle ===");
for (Usuario usuario : usuarios) {
// toString() generado automáticamente
System.out.println("toString(): " + usuario.toString());
// Getters generados automáticamente
System.out.println("Nombre: " + usuario.getNombre() +
", Email: " + usuario.getEmail() +
", Activo: " + usuario.isActivo());
}
// equals() y hashCode() generados automáticamente
Usuario usuarioCopia = new Usuario();
usuarioCopia.setNombre(usuarios[0].getNombre());
usuarioCopia.setEmail(usuarios[0].getEmail());
usuarioCopia.setFechaCreacion(usuarios[0].getFechaCreacion());
usuarioCopia.setActivo(usuarios[0].isActivo());
System.out.println("¿Son iguales usuario1 y usuarioCopia? " +
usuarios[0].equals(usuarioCopia));
}
}
Configuración de VS Code para Gradle y Lombok
Configuración específica para Gradle en settings.json
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic",
"java.saveActions.organizeImports": true,
"java.format.settings.url": "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml",
"lombok.enabled": true,
"gradle.nestedProjects": true,
"gradle.synchronization.enabled": true,
"gradle.experimental.refreshDependencies": true
}
Configuración en launch.json para debugging con Gradle
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch App (Gradle)",
"request": "launch",
"mainClass": "com.ejemplo.App",
"projectName": "mi-proyecto-gradle",
"classPaths": ["${workspaceFolder}/build/classes/java/main"],
"vmArgs": "-javaagent:${userHome}/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.30/lombok-1.18.30.jar"
}
]
}
Mejores Prácticas para Gradle
- Usar ext block para variables globales
- Aprovechar los plugins oficiales
- Configurar wrapper para consistencia de versiones
- Usar buildSrc para lógica compleja de build
- Configurar annotation processors correctamente para Lombok
- Aprovechar builds incrementales para mejor rendimiento
Troubleshooting Gradle
Problemas comunes con Gradle y Lombok
- Lombok no funciona: Verificar que tanto
compileOnlycomoannotationProcessorestén configurados - Errores de compilación: Asegurar que annotation processor esté configurado para compile y test
- Métodos no reconocidos: Ejecutar
./gradlew clean buildy recargar proyecto - Build falla: Verificar sintaxis de build.gradle y compatibilidad de versiones
- Dependencias no resuelven: Revisar repositorios configurados y conectividad
- Wrapper no funciona: Verificar permisos de ejecución en gradlew
COMPARACIÓN Y CONCLUSIONES
Comparación: Maven vs Gradle
| Aspecto | Maven | Gradle |
|---|---|---|
| Configuración | XML (pom.xml) | Groovy/Kotlin DSL (build.gradle) |
| Curva de aprendizaje | Más fácil para principiantes | Más flexible, requiere más conocimiento |
| Rendimiento | Más lento en builds grandes | Más rápido, builds incrementales |
| Ecosistema | Muy maduro, amplia adopción | Moderno, creciente adopción |
| Flexibilidad | Menos flexible, más convenciones | Muy flexible, altamente personalizable |
| Configuración Lombok | Plugin del compilador | compileOnly + annotationProcessor |
| Soporte VS Code | Excelente, integración nativa | Muy bueno, extensión adicional |
Cuándo usar cada uno
Usar Maven cuando:
- Proyectos empresariales con equipos grandes
- Convenciones estrictas son preferibles
- Compatibilidad con herramientas legacy es importante
- Simplicidad en configuración es prioritaria
Usar Gradle cuando:
- Rendimiento de build es crítico
- Flexibilidad en configuración es necesaria
- Proyectos Android (Gradle es el estándar)
- Builds complejos con lógica personalizada