Project Lombok generates boilerplate code at compile time via annotations — getters, setters, constructors, builders, and logging — keeping source files clean and readable.

Setup

  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>
  

Enable annotation processing in your IDE (IntelliJ: install Lombok plugin).

Core Annotations

@Data

Generates getters, setters, toString, equals, hashCode, and a required-args constructor:

  @Data
public class User {
    private Long id;
    private String name;
    private String email;
}

// Equivalent to ~40 lines of boilerplate
  

@Getter / @Setter

Field-level or class-level:

  @Getter
@Setter
public class Product {
    private String sku;
    @Setter(AccessLevel.NONE)
    private Instant createdAt;  // no setter
}
  

@Builder

Fluent builder pattern:

  @Builder
@Data
public class Order {
    private Long id;
    private String customerId;
    private BigDecimal total;
    private List<OrderItem> items;
}

Order order = Order.builder()
    .customerId("C-123")
    .total(new BigDecimal("99.99"))
    .items(List.of(new OrderItem("SKU-1", 2)))
    .build();
  

@NoArgsConstructor / @AllArgsConstructor

  @NoArgsConstructor
@AllArgsConstructor
@Data
public class Address {
    private String street;
    private String city;
    private String zipCode;
}
  

Required by JPA entities and Jackson deserialization.

Logging Annotations

  @Slf4j
@Service
public class OrderService {
    public void processOrder(Long id) {
        log.info("Processing order {}", id);
        log.debug("Order details: {}", order);
    }
}
  

Generates: private static final Logger log = LoggerFactory.getLogger(OrderService.class);

Also available: @Log4j2, @CommonsLog, @JBossLog.

Advanced Annotations

@RequiredArgsConstructor

Constructor for final fields (enables constructor injection):

  @RequiredArgsConstructor
@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final PaymentService paymentService;
    // constructor generated automatically
}
  

@Value (Immutable)

  @Value
public class Point {
    int x;
    int y;
    // all fields private final, getters only, no setters
}
  

@With (Immutable copies)

  @With
@Value
public class User {
    Long id;
    String name;
    String email;
}

User updated = user.withName("Alice Smith");  // new instance
  

@SneakyThrows

Bypasses checked exception declaration:

  @SneakyThrows
public void readFile(String path) {
    Files.readString(Path.of(path));  // no throws IOException needed
}
  

Use sparingly — hides exception contracts.

@UtilityClass

  @UtilityClass
public class StringUtils {
    public static boolean isBlank(String s) {
        return s == null || s.trim().isEmpty();
    }
}
// private constructor, all methods static
  

JPA Entity Example

  @Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(unique = true)
    private String email;
}
  

Lombok vs Records (Java 16+)

Feature Lombok @Value Java Record
Mutability Immutable Immutable
Boilerplate Annotation needed Built-in
Inheritance Supported Not supported
JPA entity Works Limited
Builder @Builder Manual

Use records for DTOs and value objects; Lombok for JPA entities and complex classes.

Best Practices

  • Use @RequiredArgsConstructor for Spring service injection
  • Combine @Builder with @NoArgsConstructor + @AllArgsConstructor for JPA
  • Prefer @Slf4j over manual logger declaration
  • Avoid @Data on JPA entities — use @Getter/@Setter ( @Data generates equals/hashCode including lazy fields)
  • Use Java records for simple immutable DTOs instead of Lombok when possible