Annotation-Driven CRUD Operations with MyBatis and Lombok
Lombok streamlines Java development by generating boilerplate code at compile time through annotations. To integrate it, add the following dependency:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
Core annotations include @Getter and @Setter for property accessors, @ToString for debugging output, @EqualsAndHashCode for object comparison, and the composite @Data annotation which bundles all four. For constructor generation, @NoArgsConstructor creates empty constructors while @AllArgsConstructor generates ones initializing all instance fields.
Consider a traditional entity without Lombok:
package com.example.persistence.domain;
public class Product {
private Long identifier;
private String productCode;
private Integer availableUnits;
public Long getIdentifier() {
return identifier;
}
public void setIdentifier(Long identifier) {
this.identifier = identifier;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public Integer getAvailableUnits() {
return availableUnits;
}
public void setAvailableUnits(Integer availableUnits) {
this.availableUnits = availableUnits;
}
@Override
public String toString() {
return "Product{" +
"identifier=" + identifier +
", productCode='" + productCode + '\'' +
", availableUnits=" + availableUnits +
'}';
}
}
Using Lombok annotations, this reduces to:
package com.example.persistence.domain;
import lombok.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private Long identifier;
private String productCode;
private Integer availableUnits;
}
To configure MyBatis connectivity, populate application.properties with you're database credentials:
spring.datasource.url=jdbc:mysql://localhost:3306/warehouse_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=db_admin
spring.datasource.password=secure_pass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Define the repository interface using @Mapper too trigger MyBatis proxy generation:
package com.example.persistence.repository;
import com.example.persistence.domain.Product;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface ProductRepository {
@Delete("DELETE FROM inventory WHERE item_id = #{itemId}")
void removeById(Long itemId);
@Select("SELECT * FROM inventory")
List<Product> fetchAllItems();
@Insert("INSERT INTO inventory(product_code, quantity) VALUES(#{productCode}, #{availableUnits})")
@Options(useGeneratedKeys = true, keyProperty = "identifier")
void persist(Product entity);
@Update("UPDATE inventory SET product_code = #{productCode}, quantity = #{availableUnits} WHERE item_id = #{identifier}")
void modify(Product entity);
}
Verify functionality through integration testing:
package com.example.persistence;
import com.example.persistence.domain.Product;
import com.example.persistence.repository.ProductRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class PersistenceLayerTests {
@Autowired
private ProductRepository repository;
@Test
void verifyDeletion() {
repository.removeById(6L);
}
@Test
void verifyRetrieval() {
List<Product> items = repository.fetchAllItems();
items.forEach(System.out::println);
}
@Test
void verifyInsertion() {
Product newItem = new Product(null, "TECH-001", 100);
repository.persist(newItem);
}
@Test
void verifyUpdate() {
Product existing = new Product(1L, "TECH-002", 50);
repository.modify(existing);
}
}