Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
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
more
Archives
Today
Total
관리 메뉴

josolha

JPA의 @Builder , @Builder.Default 본문

Spring

JPA의 @Builder , @Builder.Default

josolha 2023. 11. 13. 23:45
문제사항 

 

Spring Boot 및 Lombok을 사용한 프로젝트에서 Board 엔티티 클래스에 빌더 패턴을 적용하다.
Lombok의
@Builder 어노테이션을 하고 애플리케이션 실행 중에 NullPointerException이 발생하는 문제에 직면했다.

 

@Entity
@Table(name = "board")
@Getter
@Builder
public class Board extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ... 생략 ...

    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL)
    private List<Tag> tags = new ArrayList<>();

    // ... 생략 ...
}

 

위에는 해당 Board 엔티티이고 서비스단에서 board 객체 안에 빌더로 생성한 tag 객체를 주입하면서 에러가 발생했다.

 

빌더를 통한 null 에러

 

문제는 tags와 같은 컬렉션 필드에 대한 초기화가 이루어지지 않아서 NullPointerException 에러를 마주했다.


문제 원인

 

@Builder 어노테이션은 편리해서 여기저기 마구잡이로 사용 했지만 여기서 문제가 있었다.

바로 컬렉션 필드에 대한 자동 초기화를 제공하지 않는다는 것이다.

이로 인해 빌더를 통해 생성된 객체에서 해당 컬렉션 필드에 접근하려고 할 때 NullPointerException이 발생한다.

 

Board 클래스에 여러 컬렉션 필드(List<Tag>, List<Comment> 등)가 있었는데
Lombok의 
@Builder를 사용했을 때, 이 컬렉션들이 자동으로 초기화되지 않아 
빌더를 사용해 객체를 생성할 때,

이러한 필드들이 자동으로 초기화가 되지 않아 NullPointerException을 마주했다.

 

구체적으로 예를 들면서 이해해보자.

 

예를 들어 다음과 같은 클래스가 있을 때

@Builder
public class Example {
    private List<String> items = new ArrayList<>();
}

Example.builder().build()를 통해 객체를 생성하면,

items 필드는 new ArrayList<>()로 초기화된 것이 아니라 Null로 설정된다.

 

이유는 Lombok의 @Builder 어노테이션을 사용할 때 특정 필드의 초기화 동작에 대한 중요한 점이 있다.

기본적으로 @Builder 클래스의 필드에 대해 명시적으로 제공된 초기값을 무시한다.

대신, 빌더를 사용하여 객체를 생성할 때 해당 필드에 값이 제공되지 않으면,

그 필드는 기본 자바 초기화(예: 객체는 null, 기본 타입은 0, false 등)를 따른다.

 

여기서 @Builder.Default 어노테이션을 사용하면,

Lombok은 해당 필드에 대해 별도의 처리를 하여 명시적으로 제공된 초기값을 유지한다.

이 어노테이션을 사용하면 빌더를 통해 객체를 생성할 때 해당 필드에 값이 제공되지 않으면,

명시적으로 설정된 초기값(예: new ArrayList<>())을 사용한다.

@Builder
public class Example {
    @Builder.Default
    private List<String> items = new ArrayList<>();
}

따라서 이 경우, Example.builder().build()를 통해 객체를 생성하면 items 필드는 new ArrayList<>()로 초기화된다.


결과

 

Lombok의 @Builder 어노테이션과 함께 @Builder.Default를 사용하여 컬렉션 필드를 자동으로 초기화하도록 설정했다.

이렇게 하면 빌더를 통해 객체를 생성할 때 컬렉션 필드들이 자동으로 빈 리스트로 초기화가 된다.

다음은 변경된 코드의 예시이다.

@Entity
@Table(name = "board")
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Board extends BaseEntity {

    // ... 다른 필드 ...

    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL)
    @Builder.Default
    private List<Comment> comments = new ArrayList<>();

    // ... 다른 컬렉션 필드들 ...
}

 

이렇게 하면 해당 오류를 해결할 수 있었다.


결론

Lombok의 @Builder를 사용할 때 컬렉션과 같이 초기화가 필요한 필드에 대해서는 @Builder.Default를 사용하여 명시적인 초기값을 유지하도록 해야 한다. 이렇게 하면 빌더를 통해 생성된 객체에서도 해당 필드가 올바르게 초기화된 상태를 가질 수 있다.

 
 
 

'Spring' 카테고리의 다른 글

Eco-reading 트러블 슈팅(실시간 알림 기능)  (1) 2023.11.27
AWS S3 (이미지 다운로드 에러)  (1) 2023.11.20
스프링 (AOP)  (0) 2023.11.09
NCT PROJECT 트러블 슈팅(시큐리티)  (1) 2023.10.09
JWT를 위해  (0) 2023.08.21