Saltar al contenido principal

Proyecto Lombok

Eliminación de Código Repetitivo y Anotaciones en Spring Boot

Project Lombok es una librería de procesamiento de anotaciones en tiempo de compilación que automatiza la generación de código repetitivo (boilerplate) en aplicaciones Java, como getters, setters, constructores, métodos toString(), equals(), hashCode() y loggers.


1. ¿Qué es Lombok y cómo funciona?

Durante la compilación tradicional de Java, escribir atributos privados requiere definir explícitamente decenas de líneas de código redundante. Lombok se engancha en la fase de procesamiento de anotaciones del compilador (javac) e inyecta directamente el código de los métodos en el archivo compilado .class, manteniendo el archivo fuente .java totalmente limpio.


2. Instalación y Configuración

Para utilizar Lombok en un proyecto de Spring Boot, es necesario incluir la dependencia en el gestor de construcción:

pom.xml
<dependencies>
<!-- Dependencia de Project Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- Excluye Lombok del paquete ejecutable final ya que solo se necesita en compilación -->
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
Comprobación de la Instalación de Lombok

Tras declarar la dependencia y el procesador de anotaciones de Lombok en tu archivo de construcción, es fundamental verificar que la librería se descargó y configuró correctamente en el classpath ejecutando:

  • Maven: ./mvnw clean install (o mvn clean install)
  • Gradle: ./gradlew build (o ./gradlew --refresh-dependencies)

Este comando procesará las anotaciones y confirmará que el compilador javac reconoce las instrucciones de Lombok.


3. Catálogo Detallado de Anotaciones de Lombok

3.1. Acceso y Encapsulamiento (@Getter y @Setter)

Generan los métodos de lectura (getCampo()) y escritura (setCampo()). Pueden colocarse a nivel de clase (para todos los atributos) o sobre atributos individuales.

src/main/java/com/icesi/app/model/Product.java
package com.icesi.app.model;

import lombok.Getter;
import lombok.Setter;

// Aplica getters y setters automáticamente a todos los campos de la clase
@Getter
@Setter
public class Product {
private Long id;
private String name;

// Sobrescribe la visibilidad del setter solo para este atributo a nivel privado
@Setter(lombok.AccessLevel.PRIVATE)
private Double price;
}

3.2. Generación de Constructores

  • @NoArgsConstructor: Genera un constructor sin parámetros (requerido por frameworks como JPA e Jackson).
  • @AllArgsConstructor: Genera un constructor que acepta un parámetro por cada campo de la clase.
  • @RequiredArgsConstructor: Genera un constructor únicamente para los campos marcados como final o anotados con @NonNull. Es la forma recomendada en Spring para inyección de dependencias por constructor.
src/main/java/com/icesi/app/service/impl/ProductServiceImpl.java
package com.icesi.app.service.impl;

import com.icesi.app.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
// Genera un constructor automáticamente para 'productRepository' por ser un campo 'final'
@RequiredArgsConstructor
public class ProductServiceImpl {

// Spring inyectará automáticamente esta dependencia obligatoria sin necesidad de escribir el constructor a mano
private final ProductRepository productRepository;
}

3.3. Agrupadores de Código (@Data y @Value)

  • @Data: Combina @Getter, @Setter, @ToString, @EqualsAndHashCode y @RequiredArgsConstructor. Ideal para DTOs o POJOs simples.
  • @Value: Variante inmutable de @Data. Hace que todos los campos sean private final y no genera setters.
src/main/java/com/icesi/app/dto/UserResponseDto.java
package com.icesi.app.dto;

import lombok.Data;

// Genera getters, setters, toString, equals y hashCode para la clase DTO
@Data
public class UserResponseDto {
private Long id;
private String name;
private String email;
}

3.4. Patrones de Diseño y Logging (@Builder y @Slf4j)

  • @Builder: Produce una API de construcción fluida basada en el patrón Builder.
  • @Slf4j: Inyecta automáticamente una instancia del logger de SLF4J llamada log.
src/main/java/com/icesi/app/service/impl/NotificationService.java
package com.icesi.app.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
// Inyecta automáticamente: private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NotificationService.class);
@Slf4j
public class NotificationService {

public void sendEmail(String to, String subject) {
log.info("Enviando correo a: {} con asunto: {}", to, subject);
log.debug("Detalle técnico del envío de mensaje...");
}
}

4. Ejemplo Integrado: Uso del Patrón Builder

El patrón @Builder permite instanciar objetos complejos sin depender de constructores con múltiples parámetros:

src/main/java/com/icesi/app/model/Customer.java
package com.icesi.app.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Customer {
private Long id;
private String firstName;
private String lastName;
private String email;
private Boolean active;
}

Uso fluido del Builder en código Java:

src/main/java/com/icesi/app/DemoApplication.java
// Creación fluida y clara de un objeto Customer con Lombok Builder
Customer customer = Customer.builder()
.id(1L)
.firstName("Kevin")
.lastName("Coes")
.email("kevin@icesi.edu.co")
.active(true)
.build();

5. Advertencias y Buenas Prácticas con JPA y Lombok

Precaución al usar @Data en Entidades JPA

Evita colocar @Data en clases anotadas con @Entity de JPA si contienen relaciones relacionales bidireccionales (@OneToMany / @ManyToOne).

¿Por qué?
@Data genera de forma automática los métodos hashCode() y equals() incluyendo todos los campos de la clase. Si dos entidades se referencian mutuamente en una relación bidireccional, la ejecución de hashCode() invocará la referencia circular entre entidades provocando un fallo de desbordamiento de pila (StackOverflowError).

Recomendación:
En entidades JPA, utiliza anotaciones explícitas:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class User { ... }

Cuestionario de Autoevaluación

Cargando cuestionario...