일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 쓰레드
- 리스트
- 자바
- 도커 엔진
- 실전 자바 고급 1편
- 시작하세요 도커 & 쿠버네티스
- 스레드
- Docker
- 자바 입출력 스트림
- 김영한
- 인프런
- Java IO
- 스레드 제어와 생명 주기
- LIST
- Collection
- filewriter filereader
- 시작하세요! 도커 & 쿠버네티스
- 알고리즘
- 컨테이너
- java
- 동시성
- Thread
- 자료구조
- 멀티 쓰레드
- Kubernetes
- contatiner
- container
- 쿠버네티스
- 자바 io 보조스트림
- 도커
- Today
- Total
쌩로그
@Builder는 잘 써야 좋다. 본문
목록
- 포스팅 개요
- 본론
2-1. 일단 결론
2-2. 애플리케이션 로직
2-3. 문제 발생
2-4. 문제 해결 방향
2-5. 문제 해결 - 요약
1. 포스팅 개요
Entity 클래스에 @Builder 애너테이션을 클래스 레벨에 두었었는데,
클래스에 new ArrayList<>();
를 다음과 같이 선언했음에도 불구하고, NullPointerException
(이하 NPE)이 발생했다.
이를 해결한 포스팅이다.
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accompany", orphanRemoval = true)
List<?> 땡땡List = new ArrayList<>();
예전에 봤던 글에서 @Builder
를 주의해서 쓰자고 봤는데,,,
흠.. 이번에 마주쳤다.
2. 본론
2-1. 일단 결론
먼저 결론부터 내리자면,
클래스 레벨에 @Builder 애너테이션을 두면,
각 Entity 클래스에서 선언한 변수들은 값을 할당해준다 하더라도,
인스턴스 초기화시 변수들은 해당 변수 타입의 기본값
으로만 들어간다.
즉, 기본형 8개(short, char, int, long, float, double, boolean, byte)를 제외한 객체 타입들은 모두 어쩔 수 없이 null값으로 들어간다는 것이다.
list.add(객체);
해당 코드를 사용하면, list가 null이기 때문에, NPE가 발생한다.
2-2. 애플리케이션 로직
애플리케이션 로직을 잠시 설명하자면,

// 한명의 회원이 여러 동행에 참여할 수 있다. => 1:N
// 하나의 동행에 여러 회원이 들어올 수 있다. => 1:N
// 종합적으로 다대다 관계이다.
// 그래서 일대다 다대일 관계로 풀기위해서 Accompany_Member를 설계했다.
그래서 Accompany 인스턴스를 생성함과 동시에,
AccompanyMember 인스턴스 또한 같이 생성되도록 하고,
그 생성된 AccompanyMember 인스턴스는 Accompany엔티티의 accompanyMemberList안에 담겨야한다.
그런데 과정에서 List 객체를 불러올 수 없어서 NPE가 발생한 것이다.

2-3. 문제 발생
다음은 Entity를 PostMan을 통해서 생성하는 과정이다.
보시다시피 NPE가 발생했다.

코드를 추적해보자..
NPE가 발생했고, 어디서 발생했는지 보니,
AccompanyMemberService의 43번 라인이라고 알려준다.
딱 보면, List에 add()
메서드를 사용하다가 발생했을 것이다.

ㄹㅇ이다.

그리고 내가 log.info()
를 발라놨는데,
어떻게 나오는지 보자.

음... List가 null이라고 한다...

잡았다 요놈..
또 발라놓은 로그를 보면, 재미난 것을 발견할 수 있다.이게 재밌네..ㅎㅎ

위 로그 중에 주요한 로그를 보면, 다음과 같다.
AccompanyMember(accompanyMemberId=3, accompany=Accompany(id=3, accompanyMemberList=null),
여기에 나와있는 accompanyMemberId, id 값이 3이라고 나온다.
id에 값이 할당되었다는 건 DB에 담기긴 했다는 의미다.
DB에 담기지 않으면, id 또한 null일것이다.
왜냐하면 애초에 생성할 때 id는 할당해주지 않는다.
참고로 왜 id값이 3인가...
그건!! 바로...
내가 PostMan의 send버튼을 광클
해서 그렇다...;;
여튼 각설하고,
그런데 정작 list는 null이다....
Accompany의 Entity 클래스는 다음과 같다.
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder // 원인은 Enumu Shake it..;;
@ToString // 디버깅용
public class Accompany extends Auditable {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ACCOMPANY_ID", updatable = false)
private Long id;
@Column(name = "NICKNAME",length = 50, updatable = false)
private String nickname;
@Setter
@Enumerated(value = EnumType.STRING)
@Column(name = "LOCAL", length = 16) // ERD상 Not Null이지만, 기본 X(선택없음)로 들어가므로 nullable 표시 안함.
private Local local;
@Setter
@Column(name = "MAX_MEMBER_NUM", nullable = false) // 최대인원
private Long maxMemberNum;
@Setter
@Column(name = "ACCOMPANY_START_DATE")
private Date accompanyStartDate; // 동행 시작 날짜
@Setter
@Column(name = "ACCOMPANY_END_DATE")
private Date accompanyEndDate; // 동행 시작 날짜
@Setter
@Column(name = "TITLE", length = 100, nullable = false)
private String title;
@Lob
@Setter
@Column(name = "CONTENT", nullable = false)
private String content;
@Setter
@ColumnDefault("false") // 기본값 false로 지정
@Column(name = "RECRUIT_COMPLETE") // 기본값 false이므로, Table상 Not Null이지만, nullable 포시 안 함.
private boolean recruitComplete; // 모집 완료 여부 // 모집 완료 되면 True // boolean 기본 false.
@Setter
@Column(name = "COORDINATE_X")
private Double coordinateX;
@Setter
@Column(name = "COORDINATE_Y")
private Double coordinateY;
@Setter
@Column(name = "PLACE_NAME", length = 50)
private String placeName;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accompany", orphanRemoval = true) // orphanRemoval 연관관계가 끊어지면 자동으로 삭제
private List<AccompanyMember> accompanyMemberList = new ArrayList<>();
public void setAccompanyInit(String nickname) {
this.nickname = nickname;
}
원인은 클래스 레벨에 있는 @Builder
애너테이션이노무쉐이킷이 문제였다.

클래스 레벨에 @Builder
를 붙였기 때문에,
인스턴스 초기화시 모든 선언된 변수들은 각 타입의 기본값으로 들어간다.
자바에서는 8개의 기본형 외에는 다 참조형이고,
참조형은 모두 null이 기본값이기 때문에,
List<AccompanyMember> accompanyMember = new ArrayList<>();
이렇게 ArrayList를 할당해주었더라도 결국 null일 수 밖에 없는 것이다.
2-4. 문제 해결 방향
그래서 클래스 레벨에 붙이던 @Builder
애너테이션을 지우고,
새로 생성자를 만들어서 새로만든 생성자에 @Builder
를 붙이기로 했다.
다음은 새로 만든 생성자이다.

2-5. 문제 해결
이제 문제 없이 잘 들어간다.

3. 요약
Entity 클래스에 @Builder 애너테이션을 클래스 레벨
에 두었었는데,
클래스에 다음과 같이new ArrayList<>();
이렇게 값을 할당했음에도 NPE가 발생했었다.
그래서
Entity에 생성자를 따로 작성했고,
이 작성한 생성자에 @Builder
를 붙여줌으로써,
Entity클래스의 변수에 할당한 값이 정상적으로 초기화되도록 하여 문제를 해결했다.
끝.
'TroubleShooting & 고민 > BE' 카테고리의 다른 글
Test코드 작성시 Post를 작성한다면, Map을 사용해보자. (0) | 2023.07.24 |
---|---|
검색 조건을 가진 Condition클래스 작성시 바인딩 되지 않던 문제 해결 (0) | 2023.07.23 |
AOP는 필요없었다...(feat. Spring Security는 진짜 좋은 프레임워크다.) (0) | 2023.07.09 |
AOP로 AccessToken 검증(빡쳐서 만듬) (5) | 2023.07.05 |
Header에 JWT가 잘 들어갔지만...(NPE 해결, feat. 오타를 주의하자) (0) | 2023.06.26 |