엔티티에서@Builder를 사용해 보면서 생긴 문제점이 있다.
엔티티는 불변성을 유지해줘야 한다는 점을 간과했다는 점이다.
불변성이란?
변경을 허용하지 않는 성질로
불변성을 유지하는 객체란 변경 불가한 객체를 뜻한다.
불변객체는 객체를 생성 후 객체에 저장된 값을 수정하려고 시도한다면,
값이 수정되는 것이 아닌 아예 새로운 객체가 생성되어 저장된다.
예로 들면 문자열이 있다.
String a = "hello"; // 불변객체
String b = a.toUpperCase(); // a는 변하지 않고, 새 객체가 생성됨
StringBuilder sb = new StringBuilder("hello"); // 가변객체
sb.append(" world"); // 기존 객체 자체가 변경됨
@Setter는 가변객체에서 사용된다.
Emp emp = new Emp(); // 기본 생성자로 객체 생성
emp.setEmpId(empDto.getEmpId()); // 하나씩 setter 호출
객체의 변경을 허용하기에 가변객체에 해당한다.
근데 @Builder도 내부적으로 setter처럼 필드에 값을 저장하는데 반환타입이 있는 것뿐이다.
- @Setter : 객체를 생성하고 필드에 하나하나 값을 넣음.
- @Builder : 한 개씩 필드에 값을 넣고, 모아서 한 번에 객체를 생성함.
아래 접은 글은 Emp 엔티티 클래스에 @Builder를 붙였을 때,
자동생성되는 내부 클래스의 예시이다.
사원테이블(Emp)에는 3개의 필드가 있다고 가정했다.
사원번호 : emp_id
사원명 : emp_name
이메일 : email
@Entity
// 나머지 어노테이션 생략
public class Emp{
private String empid;
/// ... 나머지 필드 생략
public static class EmpBuilder {
private String empId;
private String empName;
private String email;
public EmpBuilder empId(String empId) {
this.empId = empId; // setter-like
return this;
}
public EmpBuilder empName(String empName) {
this.empName = empName; // setter-like
return this;
}
public Emp build() {
return new Emp(empId, empName, email); // 마지막에 객체 생성
}
}
}
Builder 방식은 최종적으로 생성되는 엔티티의 불변성을 직접적으로 깨지는 않는다.
다만 엔티티를 생성하는 과정에서 가변적인 중간 객체(Builder)를 사용하게 되며,
이로 인해 엔티티 생성 과정 자체가 단계적으로 열리게 된다.

예를들어 Emp class에 @Builder를 사용했다면
중간 객체는 내부클래스인 EmpBuilder 객체를 의미하고
build() 메서드로 반환되는 최종 객체는 외부클래스인 Emp 객체를 의미한다.
즉, 결과로 만들어지는 Emp 엔티티는 불변일 수 있지만,
그 생성 과정에는 가변 상태가 포함된다.
이 점에서 엔티티처럼 생성 시점의 일관성과 제약이 중요한 객체에는
@Builder 방식이 적합하지 않을 수 있다.
실제 런타임 환경에서 Builder의 중간 상태에 외부에서 접근하는 것은
구조적으로 어렵지만,
엔티티 생성 과정이 가변 객체를 포함한다는 점 자체가
설계 관점에서는 주의할 부분이 된다.
이러한 이유로 엔티티는 생성 시점의 상태와 규칙을 명확히 드러낼 수 있는
파라미터 생성자나 static factory 메서드를 통해 생성하는 것이 바람직하다.
static factory 메서드를 사용하면
엔티티 생성에 필요한 필수 값과 도메인 규칙을 한 곳에 모을 수 있고,
엔티티가 항상 일관된 상태로 생성되도록 강제할 수 있다.
@Builder의 원래 용도
그럼 @Builder는 어디에 쓰이느냐?
바로 기존에도 메서드체이닝을 사용하던 클래스이다.
그 메서드체이닝에 get 같은 코드를 줄여주려고 사용하는 것이다.
예를 들면 로그인에 사용되는 Spring Security 코드가 있다.
즉, @Builder는 객체 자체의 불변성을 보장하기 위한 도구라기보다는,
복잡한 옵션 조합이나 메서드 체이닝을 가독성 있게 표현하기 위한 도구이다.
정리하면, @Builder는 최종 객체의 불변성을 깨지는 않지만,
엔티티 생성 과정에 가변 중간 상태를 도입한다는 점에서
도메인 규칙과 일관성이 중요한 엔티티에는 적합하지 않다.
'Java' 카테고리의 다른 글
| [Spring Boot] Entity <-> DTO 변환 방법 4가지, Setter부터 @Builder, static Factory 메서드 패턴, 상속까지 (0) | 2026.01.23 |
|---|---|
| 카멜케이스와 스네이크케이스 언제 사용할까? (0) | 2026.01.08 |
| Spring Boot 버전 2 부터 자동화된 필터 기능들 (0) | 2025.12.31 |
| [Java] 날짜 타입(LocalDate, Date) 다루기, Servlet, Spring, Spring Boot (0) | 2025.09.01 |
| 백준 1931번 회의실 지정,Java 풀이 (4) | 2025.07.11 |
