[기획 & PM & BE] BE:OUR 프로젝트
[BE:OUR] Entity 클래스 어노테이션 @Builder, @AllArgsConstructor, @NoArgsConstructor
SemInDev
2025. 6. 22. 19:32
일반적으로 Entity 클래스에 @Builder, @AllArgsConstructor, @NoArgsConstructor 어노테이션을 한 번에 붙여 코드를 작성하곤 한다. 나도 그래왔는데, 이번에 코드 리뷰를 하며 이를 엄격하게 관리하는 방법에 대해 공부하고, PR을 작성해보았다.
(수정 전 코드)
package com.beour.token.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Builder
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class RefreshToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String loginId;
private String refresh;
private String expiration;
}
(수정 후 코드)
package com.beour.token.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.*;
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RefreshToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String loginId;
private String refresh;
private String expiration;
@Builder
public RefreshToken(String loginId, String refresh, String expiration) {
this.loginId = loginId;
this.refresh = refresh;
this.expiration = expiration;
}
}
수정한 코드는 불필요한 어노테이션을 제거하고,
객체 생성 방식(Builder + 생성자 접근 제어)을 명확하게 다듬은 구조입니다.
아래에 두 버전의 차이점, 그리고 장단점을 상세히 비교해드릴게요.
✅ 변경 요약
항목 수정 전 수정 후
@AllArgsConstructor | O | ❌ 제거 |
@Builder | 클래스에 붙음 | 생성자에 붙음 |
@NoArgsConstructor | 기본 (public) | access = PROTECTED |
생성자 정의 | 없음 (롬복에 의존) | 명시적으로 정의 |
접근 제어 | 모두 public 생성자 | protected 생성자 (JPA 용), 나머지는 빌더만 허용 |
✅ 장점
1. 불변 객체에 더 가까워짐
- 생성자와 필드에 Setter가 없고,
- 생성은 오직 @Builder로만 가능 → 불변 객체처럼 동작합니다.
2. 명확한 생성자 구조
- @Builder를 생성자에 붙이면,
어떤 필드들이 객체 생성에 사용되는지 명확하게 드러납니다. - 실수로 id 같은 DB 자동 생성 필드를 포함하는 것을 방지할 수 있어요.
3. JPA에서만 허용되는 생성자 제한
- @NoArgsConstructor(access = PROTECTED)로 설정하면,
외부에서 실수로 new RefreshToken()을 호출하지 못하게 제한됩니다. - 하지만 JPA 내부에서는 기본 생성자가 필요하므로 문제 없이 작동합니다.
4. 불필요한 어노테이션 제거
- @AllArgsConstructor는 Builder와 겹치는 경우가 많기 때문에 제거한 것이 바람직합니다.
❗ 단점 또는 고려할 점
1. 생성자 직접 작성 필요
- 이전에는 롬복이 모든 생성자를 자동으로 만들어줬지만,
지금은 명시적으로 생성자를 작성해야 하므로 코드가 약간 늘어납니다.
2. 전체 필드 생성자가 필요하다면 직접 추가해야 함
- 예: 테스트 코드 등에서 모든 필드를 한 번에 세팅하고 싶은 경우
- 하지만 id가 자동 생성 필드라면 보통 생성자에서 포함하지 않는 게 맞습니다.
🧾 정리 – 장단점 표
구분 설명
✅ 장점 | - 불변 객체처럼 설계됨- 생성자 + 빌더 구조가 명확- JPA 기본 생성자만 허용- 불필요한 어노테이션 제거 |
⚠️ 단점 | - 생성자 수동 작성 필요- 필요 시 모든 필드를 세팅하는 생성자를 추가해야 함 (테스트 등) |
✨ 결론
수정하신 방식이 더 깔끔하고 안전한 방식입니다.
특히 JPA + DDD 스타일, 혹은 실무에서 유지보수가 쉬운 코드를 위해
이러한 구조가 널리 권장되고 있어요.
[참고 자료]
@Builder, @All/NoArgsConstructor 제대로 알고 사용하자!