| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 시작하세요 도커 & 쿠버네티스
- SQL
- Thread
- 데이터베이스
- 동시성
- 실전 자바 고급 1편
- 알고리즘
- 쿠버네티스
- 도커
- 인프런
- 스레드
- 컨테이너
- 쓰레드
- 도커 엔진
- java
- RDB
- 멀티 쓰레드
- Java IO
- 김영한
- Kubernetes
- container
- db
- 자바
- Docker
- 람다
- 자바 입출력 스트림
- 함수형 인터페이스
- 자료구조
- mysql
- lambda
- 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 |