រៀនប្រើ Lombok annotations ដើម្បីកាត់បន្ថយ boilerplate code នៅក្នុង Spring Boot project
នៅក្នុង Spring Boot project ធម្មតា, យើងតែងសរសេរ POJO / Entity class ដែលមាន fields ច្រើន ហើយ IDE generate ចេញ getter/setter ដ៏វែង។ Lombok ជួយកាត់បន្ថយ code ទាំងនោះដោយគ្រាន់តែដាក់ annotation ងាយៗ។
បើប្រើ Maven, បន្ថែម Lombok dependency:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
ចូល Settings → Plugins → ស្វែងរក "Lombok" → Install → Restart IDE
ហើយបើក Settings → Build → Compiler → Annotation Processors → Enable annotation processing
log ដើម្បីប្រើ logging ភ្លាមៗក្រោយប្រើ @Data code ខ្លីណាស់ ប្រៀបទៅនឹងការសរសេរដោយដៃ:
public class User { private Long id; private String name; private String email; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String n){ this.name = n; } // ... getter/setter ជាច្រើនទៀត public String toString() {...} public boolean equals(...) {...} }
@Data public class User { private Long id; private String name; private String email; } // Lombok generate ជូន: // ✓ getId(), setId() // ✓ getName(), setName() // ✓ getEmail(), setEmail() // ✓ toString() // ✓ equals() & hashCode() // ✓ constructor()
ការប្រើ Lombok ជាមួយ JPA Entity — ត្រូវបន្ថែម @NoArgsConstructor ផងដែរ ព្រោះ JPA ត្រូវការ default constructor:
package com.example.demo.entity; import jakarta.persistence.*; import lombok.*; @Entity @Table(name = "products") @Data @NoArgsConstructor @AllArgsConstructor @Builder public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; private String description; @Column(nullable = false) private Double price; private Integer stock; }
@Data ជាមួយ JPA Entity ត្រូវប្រយ័ត្ន! ខ្លះណែនាំប្រើ @Getter @Setter @ToString ដាច់ដោយឡែក ដើម្បីជៀសវាង issue ជាមួយ Hibernate lazy loading។
DTO (Data Transfer Object) ប្រើ Lombok បានប្រកបដោយសុវត្ថិភាព:
package com.example.demo.dto; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ProductDto { private Long id; private String name; private String description; private Double price; private Integer stock; }
ជំនួស @Autowired ដោយប្រើ Constructor Injection ជាមួយ @RequiredArgsConstructor — វិធីដែល Spring ណែនាំ:
@Service public class ProductService { @Autowired private ProductRepository repo; @Autowired private ProductMapper mapper; }
@Service @RequiredArgsConstructor public class ProductService { private final ProductRepository repo; private final ProductMapper mapper; // Lombok inject constructor! }
package com.example.demo.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; @Slf4j @Service @RequiredArgsConstructor public class ProductService { private final ProductRepository productRepository; public List<Product> getAllProducts() { log.info("Fetching all products..."); return productRepository.findAll(); } public Product createProduct(ProductDto dto) { log.info("Creating product: {}", dto.getName()); Product product = Product.builder() .name(dto.getName()) .description(dto.getDescription()) .price(dto.getPrice()) .stock(dto.getStock()) .build(); return productRepository.save(product); } }
@Builder ជួយ construct object ក្នុង readable style ពិសេសសម្រាប់ object ដែលមាន fields ច្រើន:
// ❌ Constructor ធម្មតា — ច្រឡំ arguments Product p = new Product(null, "Phone", "Smartphone", 299.99, 50); // ✅ Builder Pattern — ច្បាស់លាស់ Product product = Product.builder() .name("iPhone 16") .description("Apple Smartphone") .price(999.99) .stock(100) .build(); // @Builder ជាមួយ default value @Builder.Default private Boolean active = true; @Builder.Default private LocalDateTime createdAt = LocalDateTime.now();
ជំនួស Logger logger = LoggerFactory.getLogger(...) ដ៏វែងដោយ @Slf4j:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyController { private static final Logger log = LoggerFactory .getLogger( MyController.class ); }
import lombok.extern.slf4j.Slf4j; @Slf4j public class MyController { // ប្រើ log បានភ្លាម! log.info("Hello {}", name); log.error("Error: {}", e); log.debug("Debug msg"); }
package com.example.demo.controller; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @Slf4j @RestController @RequestMapping("/api/products") @RequiredArgsConstructor public class ProductController { private final ProductService productService; @GetMapping public ResponseEntity<?> getAll() { log.info("GET /api/products"); return ResponseEntity.ok( productService.getAllProducts() ); } @PostMapping public ResponseEntity<?> create( @RequestBody ProductDto dto) { log.info("POST /api/products: {}", dto); return ResponseEntity.ok( productService.createProduct(dto) ); } }
final fields ជំនួស @Autowired — Spring ណែនាំ constructor injection
@Getter @Setter @ToString(exclude="...") ដើម្បីជៀស lazy loading infinite loop
import lombok.Value; @Value // fields ទាំងអស់ final + @Getter only public class ErrorResponse { String message; Integer statusCode; String timestamp; } // ប្រើ: var err = new ErrorResponse( "Not Found", 404, "2025-01-01" );