클래스 단위로 @Builder 사용시 필드를 전부 초기화 하지 않으면 예상하지 못한 일이 생길수도 있다.
@Entity
@Builder
public class Book {
@Id @GeneratedValue
@Column(name = "book_id")
private Long id;
@Column(name = "book_name")
private String name;
@Column(name = "book_isbn")
private String isbn;
@Enumerated(EnumType.STRING)
@Column(name = "book_category")
private BookCategory category;
@OneToMany(mappedBy = "book")
private List<Post> posts = new ArrayList<>();
}
스프링 프로젝트를 하던중,
이런식으로 엔티티를 만들어 놨었다.
그리고 테스트코드를 짜는데 자꾸 NPE가 떴다.
posts가 null로 초기화 된 것이 문제였다.
하지만 난 분명히 마지막줄에
List<Post> posts = new ArrayList<>(); 이렇게 해놨으니
null일리가 없는데? 하고 생각했으나....
내 테스트코드는
Post post = Post.builder()
.type(PostType.MEMO)
.scope(PostScope.PUBLIC)
.isIncomplete(Boolean.TRUE)
.imgLocation("123이미지123")
.title("책을 읽고")
.content("짱")
.build();
이렇게
posts를 빌더에서 만들어주지 않았었다.
이렇게 하면 리스트가 null로 초기화 된다.
이걸 방지하기 위해서 디폴트값을 설정해줄수 있다.
롬복 공식문서
https://projectlombok.org/features/Builder
@Builder.Default
If a certain field/parameter is never set during a build session, then it always gets 0 / null / false. If you've put @Builder on a class (and not a method or constructor) you can instead specify the default directly on the field, and annotate the field with @Builder.Default:
@Builder.Default private final long created = System.currentTimeMillis();
이렇게 써있다.
그래서
@Entity
@Builder
public class Book {
@Id @GeneratedValue
@Column(name = "book_id")
private Long id;
@Column(name = "book_name")
private String name;
@Column(name = "book_isbn")
private String isbn;
@Enumerated(EnumType.STRING)
@Column(name = "book_category")
private BookCategory category;
@Builder.Default
@OneToMany(mappedBy = "book")
private List<Post> posts = new ArrayList<>();
}
이렇게 써줘서 급한불을 꺼보았다.
더 찾아보다가 이런 글을 봤다.
https://cheese10yun.github.io/spring-builder-pattern/
제대로된 방어적 프로그래밍을 하려면 이분이 한 대로 따라해야겠다.
'Dev > Spring' 카테고리의 다른 글
테스트 작성과 Jacoco (0) | 2022.04.13 |
---|---|
Controller와 Service의 역할에 대한 고민 (2) | 2021.12.17 |
Servlet 서블릿에 대하여 (0) | 2021.07.17 |
9. 빈 스코프 (0) | 2021.03.28 |
8. 빈 생명주기 콜백 (0) | 2021.03.28 |