Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- React
- DevOps
- 클린 아키텍처
- OpenSearch
- 글또10기
- axios
- UserLand
- constructor
- 헥사고날 아키텍처
- 3계층 아키텍처
- design-pattern
- builder-pattern
- object-creation
- HashMap
- 가용영역
- 다짐글
- 포트앤어댑터 아키텍처
- 코딩테스트
- 글또
- 클라우드아키텍처
- Level2
- 글쓰기세미나
- 회고
- 코엑스그랜드볼룸
- 레벨1
- QueryDSL
- 프로그래머스
- ReverseNested
- static-factory-method
- SpringBoot
Archives
- Today
- Total
oguri's garage
Lombok 어노테이션(@Builder, @NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor, @Data) 본문
개발하다/Spring
Lombok 어노테이션(@Builder, @NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor, @Data)
oguri 2025. 10. 2. 23:071. 기본 생성자 어노테이션
@NoArgsConstructor
- 매개변수가 없는 기본 생성자를 생성
@NoArgsConstructor
public class User {
private String name;
private String email;
}
// 생성되는 코드
public User() {}
접근 제어자 설정
@NoArgsConstructor(access = AccessLevel.PROTECTED) // protected 생성자
@NoArgsConstructor(access = AccessLevel.PRIVATE) // private 생성자
[!info] 왜 접근 제어자를 설정하는가?
핵심: 누가, 어떻게 이 객체를 만들 수 있는지를 통제하기 위해// public 생성자 - 누구나 접근 가능 (대문이 활짝 열린 상태) User user = new User(); // 어디서든 가능 // protected 생성자 - 같은 패키지나 상속받은 클래스만 접근 (가족만 출입 가능) User user = new User(); // 같은 패키지 내에서만 가능 // private 생성자 - 클래스 내부에서만 접근 (본인만 출입 가능) User user = new User(); // 컴파일 에러! 외부에서 접근 불가
[!info] JPA를 사용할 때 생성자의
PROTECTED접근 제어자를 사용할 것을 권장하는데 이는 JPA가 reflection을 사용해 객체를 생성하기 때문이다. 리플렉션으로 객체를 생성할 때 생성자가 private면 객체를 생성할 수 없다.
@AllArgsConstructor
모든 필드를 매개변수로 받는 생성자를 생성
@AllArgsConstructor
public class User {
private String name;
private String email;
}
// 생성되는 코드
public User(String name, String email) {
this.name = name;
this.email = email;
}
@RequiredArgsConstructor
final 이나 @NonNull 필드만을 매개변수로 받는 생성자를 생성
@RequiredArgsConstructor
public class User {
private final String name; // final 필드
@NonNull
private String email; // @NonNull 필드
private String role; // 일반 필드 (생성자에 포함되지 않음)
}
// 생성되는 코드
public User(String name, @NonNull String email) {
this.name = name;
this.email = Objects.requireNonNull(email, "email is marked non-null but is null");
}
2. @Builder 어노테이션
클래스 레벨에서 사용
@Builder
public class User {
private String name;
private String email;
}
// 사용법
User user = User.builder()
.name("John")
.email("john@example.com")
.build();
특징:
- 모든 필드를 대상으로 빌더 생성
- 기본 생성자는 private으로 생성
- 모든 필드를 포함하는 생성자도 private로 생성
생성자 레벨에서 사용
특정 필드만 선택적으로 빌더에 포함하고 싶을 때 사용
public class User {
private String name;
private String email;
private String role;
@Builder
public User(String name, String email) { // role은 제외
this.name = name;
this.email = email;
this.role = "USER"; // 기본값 설정
}
}
3. 어노테이션 조합 패턴
@Builder만 사용하는 경우
@Getter
@Builder
public class AccountInformationResponse {
private String field;
}
장점:
- 불변성을 보장
- 외부에서 직접 생성자 호출을 막을 수 있음
단점:
- JPA 엔티티나 JSON 직렬화 시 문제 발생 가능
@Builder + @NoArgsConstructor + @AllArgsConstructor
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String field;
}
필요한 경우:
- JPA 엔티티 클래스
- JSON 직렬화/역직렬화 (Jackson 라이브러리)
- Spring Framework의 일부 기능들
- 프레임워크나 라이브러리가 리플렉션을 사용하여 객체를 생성할 때
권장 패턴 (접근 제어자 활용)
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AccountEntity {
private String field;
}
이점:
- Protected 생성자로 JPA 요구사항 충족
- Private 생성자로 직접 생성은 제한
- Builder 패턴만 허용
4. 상속과 @SuperBuilder
상속 관계에서 빌더 패턴을 사용할 때는 @SuperBuilder를 사용합니다.
@SuperBuilder
public class Parent {
private String parentField;
}
@SuperBuilder
public class Child extends Parent {
private String childField;
}
// 사용법
Child child = Child.builder()
.parentField("parent") // 부모 클래스 필드
.childField("child") // 자식 클래스 필드
.build();
[!info] @SuperBuilder 를 양쪽에 선언하는 이유
@SuperBuilder는 복잡한 제네릭 구조를 사용하여 상속 체인 전체에서 빌더 패턴을 구현한다.
각 클래스가 자신만의 빌더 클래스를 생성하고, 이들이 서로 연결되어야 하기 때문이다.
내부적으로 생성되는 코드 구조는 다음과 같다.// Parent에 @SuperBuilder 적용 시 생성되는 구조 public abstract class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> { private String parentField; public B parentField(String parentField) { this.parentField = parentField; return self(); } protected abstract B self(); protected abstract C build(); } // Child에 @SuperBuilder 적용 시 생성되는 구조 public class ChildBuilder extends ParentBuilder<Child, ChildBuilder> { private String childField; public ChildBuilder childField(String childField) { this.childField = childField; return this; } @Override protected ChildBuilder self() { return this; } @Override protected Child build() { return new Child(this); } }
5. @Data와의 관계
@Data는 다음 어노테이션들을 포함합니다:
@Getter: 모든 필드에 대한 getter 메서드 생성@Setter: 모든 필드에 대한 setter 메서드 생성@ToString: 모든 필드를 포함하는 toString() 메서드 생성@EqualsAndHashCode: equals()와 hashCode() 메서드 생성@RequiredArgsConstructor: 필수 인자를 포함하는 생성자 생성- final 필드나 @NonNull로 마크된 필드들을 파라미터로 받는 생성자 생성
- 만약 해당하는 필드가 없다면 no-args 생성자로 생성
@Data
public class User {
private final String name; // final 필드
private String email; // 일반 필드
}
// @RequiredArgsConstructor에 의해 final 필드만 포함하는 생성자 생성
6. 주의사항
- @Builder만 사용할 경우 리플렉션 기반 라이브러리 사용 시 문제 발생 가능
- @NoArgsConstructor 사용 시 필드의 초기화 값 주의 필요
- 상속 관계에서는
@Builder대신@SuperBuilder사용 필요 - JPA 엔티티에서는 protected 기본 생성자가 필요함
'개발하다 > Spring' 카테고리의 다른 글
| (Spring) Jackson 역직렬화 동작 방식과 안전한 코딩 패턴 (0) | 2025.10.04 |
|---|---|
| Spring vs Spring Boot 핵심 차이점 (0) | 2025.10.03 |
| QueryDSL Q-Type 클래스 - 개념, 생성, 활용법 (0) | 2025.10.01 |
| Spring 검증 어노테이션 (@Valid, @NotNull, @NotEmpty, @NotBlank) (1) | 2025.09.29 |
| 쉽게쉽게 알아보는 헥사고날 아키텍처! (8) | 2024.10.30 |