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
Introduction to Lombok
Section titled “Introduction to Lombok”What is Lombok?
Section titled “What is Lombok?”- 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)
Why Use Lombok in Spring Boot 3?
Section titled “Why Use Lombok in Spring Boot 3?”- 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
Setup & Configuration
Section titled “Setup & Configuration”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.configconfig.stopbubbling = truelombok.anyConstructor.addConstructorProperties = truelombok.addLombokGeneratedAnnotation = truelombok.experimental.flagUsage = WARNINGlombok.accessors.chain = trueCore Annotations
Section titled “Core Annotations”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@AllArgsConstructorpublic 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@Setterpublic class Product { @Id private Long id; private String name; private BigDecimal price;}3. @Builder - Implements Builder pattern
Section titled “3. @Builder - Implements Builder pattern”- Generates: Builder class for fluent object creation
- Use case: Complex object construction with many parameters
@Service@RequiredArgsConstructorpublic 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@RequiredArgsConstructorpublic class OrderService { private final OrderRepository orderRepository; private final PaymentService paymentService; // Constructor automatically generated}6. @Value - Immutable data classes
Section titled “6. @Value - Immutable data classes”- Generates: All fields are private final, getters, equals, hashCode, toString
- Use case: Immutable DTOs, configuration objects, value objects
@Value@Builderpublic class UserDto { Long id; String email; String fullName;}Advanced Features
Section titled “Advanced Features”1. @With - Immutable updates
Section titled “1. @With - Immutable updates”- Generates:
withFieldName(value)methods for immutable updates - Use case: Functional programming style, configuration updates
@Value@Builder@Withpublic class ImmutableConfig { String apiKey; int timeout;}
// UsageImmutableConfig config = new ImmutableConfig("key", 30);ImmutableConfig updated = config.withTimeout(60);2. @Singular - Collection builders
Section titled “2. @Singular - Collection builders”- Generates: Builder methods for adding single elements to collections
- Use case: Building objects with collections in a fluent way
@Data@Builderpublic 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@Slf4jpublic 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}Spring Boot Integration
Section titled “Spring Boot Integration”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@Validatedpublic 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@AllArgsConstructorpublic 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@Builderpublic class CreateUserRequest { @NotBlank private String email; private String firstName; private String lastName;}
// Response DTO@Value@Builderpublic 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@Slf4jpublic 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")@RequiredArgsConstructorpublic class UserController { private final UserService userService;
@PostMapping public UserResponse createUser(@RequestBody CreateUserRequest request) { return userService.createUser(request); }}Best Practices
Section titled “Best Practices”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@Datapublic class DatabaseProperties { @NotBlank private String url;
@Valid private Pool pool = new Pool();
@Data public static class Pool { @Min(1) private int maxSize = 10; }}4. Testing with Lombok - Clean test code
Section titled “4. Testing with Lombok - Clean test code”- Use: Builders for test data creation
- Leverage: @Builder in test fixtures
- Keep: Test classes clean and readable
@Data@Builderclass TestUser { private Long id; private String username;}
class UserServiceTest { @Test void shouldCreateUser() { TestUser testUser = TestUser.builder() .id(1L) .username("testuser") .build();
// Test logic }}Common Pitfalls
Section titled “Common Pitfalls”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)@AllArgsConstructorpublic 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@Withpublic 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@Builderpublic class ProductFilter { @Builder.Default private Optional<String> category = Optional.empty();
public static class ProductFilterBuilder { public ProductFilter build() { // Custom validation return new ProductFilter(category); } }}Performance Considerations
Section titled “Performance Considerations”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
@Datapublic 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)@Datapublic class LargeObject { private String field1; // ... many fields}Migration Strategy
Section titled “Migration Strategy”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 boilerplatepublic class TraditionalUser { private Long id; private String name; // ... getters, setters, constructors, equals, hashCode, toString}
// After: 5 lines with same functionality@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class ModernUser { private Long id; private String name;}Conclusion
Section titled “Conclusion”Key Takeaways:
Section titled “Key Takeaways:”- 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
Recommended Approach:
Section titled “Recommended Approach:”- Start with @Data and @Builder for new entities
- Use @RequiredArgsConstructor for Spring services
- Apply @Value for immutable DTOs
- Configure lombok.config for project consistency
- Follow best practices to avoid common pitfalls