Skip to content

Project Lombok

Lombok is a Java library that automatically plugs into your editor and build tools, spicing up your Java code by generating boilerplate code through annotations

  • Java library that reduces boilerplate code through annotations
  • Automatically generates getters, setters, constructors, equals, hashCode, toString
  • Plugins available for all major IDEs (IntelliJ, Eclipse, VS Code)
  • Reduces boilerplate by 50-80% in typical Spring Boot applications
  • Improves readability by keeping classes clean and focused
  • Maintains clean domain models without cluttering business logic
  • Reduces maintenance overhead and human error

1. Maven Configuration - Add Lombok dependency to your project

Section titled “1. Maven Configuration - Add Lombok dependency to your project”
Add Lombok dependency to your project
<!-- pom.xml -->
<dependencies>
<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>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

2. IDE Setup - Configure your development environment

Section titled “2. IDE Setup - Configure your development environment”
  • Install Lombok plugin for your IDE
  • Enable annotation processing in compiler settings
  • For IntelliJ: Settings → Build → Compiler → Annotation Processors → Enable
  • VSCode: Install Lombok extension

3. lombok.config - Project-specific Lombok configuration

Section titled “3. lombok.config - Project-specific Lombok configuration”
# Root directory lombok.config
config.stopbubbling = true
lombok.anyConstructor.addConstructorProperties = true
lombok.addLombokGeneratedAnnotation = true
lombok.experimental.flagUsage = WARNING
lombok.accessors.chain = true

1. @Data - All-in-one annotation for POJOs

Section titled “1. @Data - All-in-one annotation for POJOs”
  • Generates: getters, setters, toString, equals, hashCode, required constructor
  • Use case: Simple data classes and entities
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
private Long id;
private String email;
private String firstName;
private String lastName;
}

2. @Getter/@Setter - Fine-grained access control

Section titled “2. @Getter/@Setter - Fine-grained access control”
  • Generates: Only getters or setters as specified
  • Use case: When you need partial code generation
@Entity
@Getter
@Setter
public class Product {
@Id
private Long id;
private String name;
private BigDecimal price;
}
  • Generates: Builder class for fluent object creation
  • Use case: Complex object construction with many parameters
@Service
@RequiredArgsConstructor
public class ProductService {
public Product createProduct() {
return Product.builder()
.name("Laptop")
.price(999.99)
.build();
}
}

4. @AllArgsConstructor & @NoArgsConstructor - Constructor generation

Section titled “4. @AllArgsConstructor & @NoArgsConstructor - Constructor generation”
  • @AllArgsConstructor: Creates constructor with all fields
  • @NoArgsConstructor: Creates no-argument constructor
  • Use case: JPA entities, DTOs, configuration classes
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Category {
@Id
private Long id;
private String name;
}

5. @RequiredArgsConstructor - Constructor injection for Spring

Section titled “5. @RequiredArgsConstructor - Constructor injection for Spring”
  • Generates: Constructor with final fields
  • Use case: Spring service classes with dependency injection
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentService paymentService;
// Constructor automatically generated
}
  • Generates: All fields are private final, getters, equals, hashCode, toString
  • Use case: Immutable DTOs, configuration objects, value objects
@Value
@Builder
public class UserDto {
Long id;
String email;
String fullName;
}
  • Generates: withFieldName(value) methods for immutable updates
  • Use case: Functional programming style, configuration updates
@Value
@Builder
@With
public class ImmutableConfig {
String apiKey;
int timeout;
}
// Usage
ImmutableConfig config = new ImmutableConfig("key", 30);
ImmutableConfig updated = config.withTimeout(60);
  • Generates: Builder methods for adding single elements to collections
  • Use case: Building objects with collections in a fluent way
@Data
@Builder
public class ShoppingCart {
private Long id;
@Singular
private List<CartItem> items;
@Singular("tag")
private Set<String> tags;
}

3. @Slf4j, @CommonsLog, @Log4j2 - Logger injection

Section titled “3. @Slf4j, @CommonsLog, @Log4j2 - Logger injection”
  • Generates: Logger field automatically
  • Use case: Any class that needs logging
@Service
@RequiredArgsConstructor
@Slf4j
public class PaymentService {
public void processPayment() {
log.info("Processing payment");
// Business logic
}
}

4. Customizing @ToString - Control toString output

Section titled “4. Customizing @ToString - Control toString output”
  • Controls: Which fields to include in toString
  • Use case: Excluding sensitive data, circular references
@Entity
@Data
@ToString(onlyExplicitlyIncluded = true)
public class Employee {
@Id
@ToString.Include
private Long id;
private String ssn; // Sensitive - excluded automatically
}

5. @EqualsAndHashCode - Control equality comparison

Section titled “5. @EqualsAndHashCode - Control equality comparison”
  • Controls: Which fields to use in equals and hashCode
  • Use case: Business key equality, excluding certain fields
@Entity
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Product {
@Id
@EqualsAndHashCode.Include
private Long id;
@EqualsAndHashCode.Include
private String sku; // Business key
}

1. Configuration Properties - Type-safe configuration

Section titled “1. Configuration Properties - Type-safe configuration”
  • Combines: Lombok with Spring’s @ConfigurationProperties
  • Use case: Application configuration classes
@ConfigurationProperties(prefix = "app.security")
@Data
@Validated
public class SecurityConfigProperties {
@NotBlank
private String secretKey;
@Min(1)
private int tokenExpirationMinutes = 30;
}

2. JPA Entities with Lombok - Clean entity definitions

Section titled “2. JPA Entities with Lombok - Clean entity definitions”
  • Combines: Lombok with JPA annotations
  • Use case: Database entities with minimal boilerplate
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Order {
@Id
private Long id;
@OneToMany(mappedBy = "order")
@ToString.Exclude
private List<OrderItem> items;
}

3. DTO Pattern with Lombok - Data transfer objects

Section titled “3. DTO Pattern with Lombok - Data transfer objects”
  • Separates: API layer from persistence layer
  • Use case: Request/response objects in REST APIs
// Request DTO
@Data
@Builder
public class CreateUserRequest {
@NotBlank
private String email;
private String firstName;
private String lastName;
}
// Response DTO
@Value
@Builder
public class UserResponse {
Long id;
String email;
String fullName;
}

4. Service Layer with Constructor Injection - Dependency injection

Section titled “4. Service Layer with Constructor Injection - Dependency injection”
  • Uses: @RequiredArgsConstructor for automatic constructor injection
  • Use case: Spring service classes
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
// No explicit constructor needed
public User createUser(User user) {
return userRepository.save(user);
}
}

5. Controller Layer - REST endpoint definitions

Section titled “5. Controller Layer - REST endpoint definitions”
  • Combines: Lombok with Spring MVC annotations
  • Use case: REST controller classes
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping
public UserResponse createUser(@RequestBody CreateUserRequest request) {
return userService.createUser(request);
}
}

1. Entity Best Practices - JPA and Lombok compatibility

Section titled “1. Entity Best Practices - JPA and Lombok compatibility”
  • Always include: @NoArgsConstructor for JPA compliance
  • Exclude: Bidirectional relationships from toString and equals
  • Use: @Builder for complex entity creation
@Entity
@Data
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Product {
@Id
@EqualsAndHashCode.Include
private Long id;
@OneToMany(mappedBy = "product")
@ToString.Exclude
private List<OrderItem> orderItems;
}

2. Builder Pattern Best Practices - Effective object building

Section titled “2. Builder Pattern Best Practices - Effective object building”
  • Use: @Builder(toBuilder = true) for immutable updates
  • Add: Custom builder methods for common scenarios
  • Validate: In custom build() methods
@Value
@Builder(toBuilder = true)
public class ApiResponse<T> {
boolean success;
String message;
T data;
// Predefined success response
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.success(true)
.message("Success")
.data(data)
.build();
}
}

3. Configuration Best Practices - Application configuration

Section titled “3. Configuration Best Practices - Application configuration”
  • Combine: @ConfigurationProperties with @Data
  • Use: Nested classes for complex configurations
  • Validate: Configuration with Bean Validation
@ConfigurationProperties(prefix = "app.database")
@Validated
@Data
public class DatabaseProperties {
@NotBlank
private String url;
@Valid
private Pool pool = new Pool();
@Data
public static class Pool {
@Min(1)
private int maxSize = 10;
}
}
  • Use: Builders for test data creation
  • Leverage: @Builder in test fixtures
  • Keep: Test classes clean and readable
@Data
@Builder
class TestUser {
private Long id;
private String username;
}
class UserServiceTest {
@Test
void shouldCreateUser() {
TestUser testUser = TestUser.builder()
.id(1L)
.username("testuser")
.build();
// Test logic
}
}

1. JPA and Lombok Compatibility - Avoid JPA issues

Section titled “1. JPA and Lombok Compatibility - Avoid JPA issues”
  • Problem: Missing proper constructors for JPA
  • Solution: Always include @NoArgsConstructor(access = AccessLevel.PROTECTED)
// ✅ Correct
@Entity
@Data
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class CorrectEntity {
@Id
private Long id;
}

2. Circular Dependency in toString() - Avoid StackOverflowError

Section titled “2. Circular Dependency in toString() - Avoid StackOverflowError”
  • Problem: Bidirectional relationships cause infinite recursion
  • Solution: Use @ToString.Exclude on relationship fields
@Entity
@Data
@ToString(onlyExplicitlyIncluded = true)
public class Order {
@Id
@ToString.Include
private Long id;
@OneToMany(mappedBy = "order")
@ToString.Exclude
private List<OrderItem> items;
}

3. Immutable Objects with @With - Safe object updates

Section titled “3. Immutable Objects with @With - Safe object updates”
  • Use case: Functional updates without modifying original object
  • Benefit: Thread-safe and predictable behavior
@Value
@Builder
@With
public class Configuration {
String host;
int port;
public Configuration withHttpsPort() {
return this.withPort(443);
}
}

4. Handling Optional Fields in Builders - Flexible object creation

Section titled “4. Handling Optional Fields in Builders - Flexible object creation”
  • Use: @Builder.Default for default values
  • Add: Custom validation in builder
@Data
@Builder
public class ProductFilter {
@Builder.Default
private Optional<String> category = Optional.empty();
public static class ProductFilterBuilder {
public ProductFilter build() {
// Custom validation
return new ProductFilter(category);
}
}
}

1. Lazy Getter - Optimize expensive computations

Section titled “1. Lazy Getter - Optimize expensive computations”
  • Use case: Fields that require heavy computation
  • Benefit: Computation happens only once when first accessed
@Data
public class ExpensiveResource {
@Getter(lazy = true)
private final String expensiveData = computeExpensively();
}

2. @EqualsAndHashCode Cache - Optimize frequent comparisons

Section titled “2. @EqualsAndHashCode Cache - Optimize frequent comparisons”
  • Use case: Objects with expensive equality computation
  • Benefit: Caches hashCode for better performance
@EqualsAndHashCode(cacheStrategy = EqualsAndHashCode.CacheStrategy.LAZY)
@Data
public class LargeObject {
private String field1;
// ... many fields
}

From Traditional Java to Lombok - Gradual adoption

Section titled “From Traditional Java to Lombok - Gradual adoption”
  • Start with: New classes using Lombok
  • Refactor: Existing classes gradually
  • Benefits: Immediate boilerplate reduction
// Before: 50+ lines of boilerplate
public class TraditionalUser {
private Long id;
private String name;
// ... getters, setters, constructors, equals, hashCode, toString
}
// After: 5 lines with same functionality
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ModernUser {
private Long id;
private String name;
}
  • Lombok dramatically reduces boilerplate code in Spring Boot applications
  • Proper configuration ensures compatibility with Spring Boot and JPA
  • Best practices prevent common issues and improve code quality
  • Advanced features provide powerful tools for complex scenarios
  • Gradual migration allows smooth adoption in existing projects
  1. Start with @Data and @Builder for new entities
  2. Use @RequiredArgsConstructor for Spring services
  3. Apply @Value for immutable DTOs
  4. Configure lombok.config for project consistency
  5. Follow best practices to avoid common pitfalls