티스토리 뷰

문제 발생

@ManyToOne 그리고 @OneToMany로 양방향 연관관계를 맺으면 NullPointerException이 발생하였다.

Board(게시물)와 View(조회수, 좋아요) Entity 간의 연관관계를 맺었다.

 

Board Entity

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "board_id")
    private Long id;

    private String title; // 제목
    private String content; // 내용
    private long viewCnt; // 조회수
    private long likeCnt; // 좋아요
    private LocalDateTime createdDate; // 작성 일자
    private LocalDateTime editDate; // 수정 일자

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

	// 양방향 연관관계
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "board")
    private List<View> views = new ArrayList<>();

	// 연관관계 편의 메소드
    public void relationshipToMember(Member member) {
        this.member = member;
        member.getBoards().add(this);
    }
}

 

View Entity

@Getter
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class View {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "view_id")
    private Long id;

    private long viewCnt;
    private long likeCnt;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    Member member;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "board_id")
    Board board;

	// 연관관계 편의 메소드
    public void relationshipToBoard(Board board) {
        this.board = board;
        board.getViews().add(this);
    }

	// 연관관계 편의 메소드
    public void relationshipToMember(Member member) {
        this.member = member;
        member.getViews().add(this);
    }
}

 

위 Entity가 정상적으로 사용되는지 테스트를 해보았다. View와 Board를 연관관계를 맺어주는 편의 메서드를 호출하는 순간 NullPointerException이 발생한다. 그 이유로는 "Board.getViews()" 반환값이 null이라고 한다.

 

그런데 아래 Board Entity를 보면 Builder Pattern을 사용하고 있고 views 필드를 생설할 때 new ArrayList<>()를 통해 초기화도 해주었다. 정황상 views 필드에 null이 저장될 수 없다.

문제 원인

views 필드가 null로 저장된 이유는 Builder Pattern을 사용했기 때문이다. 클래스가 인스턴스화될 때 기본적으로는 필드에 명시한 값으로 초기화된다. 그런데 위 코드는 Builder Pattern을 사용하여 객체를 생성하기 때문에 명시적으로 지정한 값으로 초기화되지 않는다.

 

그렇다면 Builder Pattern을 통해 객체를 생성할 때 값을 지정하지 않으면 어떻게 되는지 확인해보자.

BuilderClass

@Builder
@Data
public class BuilderClass {

    List<String> list = new ArrayList<>();
    Integer num1;
    int num2;
}

 

BuilderClassTest

@SpringBootTest
public class BuilderClassTest {
    @Test
    void test() {
        BuilderClass build = BuilderClass.builder()
                .build();
        System.out.println("build = " + build);
    }
}

 

지정하지 않은 값들은 다음과 같이 저장됨을 알 수 있다.

문제 해결

@Builder.Default 애너테이션을 사용하면 명시적으로 지정한 값으로 초기화된다. 즉, Builder Pattern으로 객체를 생성할 때 값을 지정하지 않은 필드에는 Entity에 명시한 값으로 초기화된다는 의미이다. 

Builder Pattern으로 객체를 생성할 때 필드 값을 지정하지 않으면 views 필드가 new ArrayList<>()로 초기화된다.

Total
Today
Yesterday
최근에 올라온 글
«   2024/11   »
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