개발 공부/트러블슈팅

@OneToMany 관계 정의 후, getter 호출 시 NullPointerException이 발생하는 원인과 문제 해결

빵다희 2024. 9. 29. 22:02

👾 문제식별

회원가입을 시도하면 기본으로 'USER' 권한을 부여받은채 가입될 수 있도록 로직을 수정하고, 기존에 작성해 두었던 테스트 코드를 실행해보았다.

 

예상치못했던 java.lang.NullPointerException이 발생하면서 테스트코드가 실패한다..!

 


🔍 원인분석

로그에 표시된 에러가 발생한 지점을 찾아가보았다.

 

MemberService.java:33

 

Member.java:71

 

Cannot invoke "java.util.List.add(Object)" because the return value of "maumnote.mano.domain.Member.getMemberRoles()" is null

 

로그에는 getMemberRoles()가 null을 반환했기 때문에 add(Object)를 호출할 수 없다고 출력되었다.

따라서 member.getMemberRoles()가 null이라

member.getMemberRoles().add(memberRole) 이렇게 작성한 코드에서 NullPointer가 발생했을것이다.

 

빙고, null이 맞다..!


🤔 해결방법시도

1. 필드 확인

List<MemberRole> memberRoles = new ArrayList<>();

 

2. 기본 생성자 호출

 

기존에는 Builder를 호출하여 인스턴스를 생성하여서, 기존 생성자로도 만들어보았다.

기본생성자로 만든 인스턴스에는 getMemberRoles() 호출 했을때 null 이 아닌 ArrayList로 초기화 되어있다.

List<MemberRole> memberRoles = new ArrayList<>();

이렇게 하드코딩으로 필드에 값을 준게 빌더패턴으로 인스턴스를 생성할때에는 적용이 안되고, 기본 생성자로 만들었을 때에는 반영되었다.


✅ 최종해결방법

그럼 방법은 2가지가 있다.

1. 기본 생성자로 객체를 만들고 필요값을 setter로 주입

2. builder 패턴으로 객체 생성 시, 기본값 정해주기

 

최근에는 값이 무분별하게 변경되지 않기 위해 setter를 만드는 걸 지양하는 편이라, 2번으로 해결방법을 알아보았다.

2-1. 빌더 클래스 재정의

2-2. @Builder.Default 사용

 

코드를 간결하게 작성하기 위해 어노테이션을 사용하는데, 그걸 무시하고 필드의 초기화를 위해 builder 코드를 작성하는건 낭비라고 했다.

간단히 시도할 수 있는 @Builder.Default 붙이기로 결정.

 

1. Member Class

builder 호출시에 특정 클래스나 컬렉션으로 초기화 필요한 필드들은

원하는 클래스로 대입을 해주고, 상단에 @Builder.Default 붙여준다.

 

2. member.getMemberRoles()

builder로 객체를 만들었어도, getMemberRoles 호출했을때 null 아니라 ArrayList가 리턴된다.

 


💡 해결 방법 설명

  •  List<MemberRole> memberRoles와 같이 자료형이 참조형인 필드는 기본생성자로 객체를 생성했을때, 그 값이 null이다.
  • 하지만  List<MemberRole> memberRoles = new ArrayList<>(); 이렇게 기본값을 명시한다면, 기본생성자로 객체를 만들었을때 정해진 클래스로 초기화 된다.
  • builder 패턴을 이용한다면, 코드를 작성하여 builder를 호출했을 때 필드가 특정 클래스로 초기화되도록 해야하는데,
  • Lombok을 이용한다면 그 과정을 편하게 할 수 있는 방법이 있다.
  • 바로, @Builder.Default 이다.

@Builder.Default 

@Default 애너테이션이 있는 필드는 초기화 표현식을 가져야 합니다. 이 표현식은 빌딩 중에 명시적으로 설정되지 않을 경우 사용될 기본값으로 사용됩니다.

 

  • 빌더 패턴에서 기본값을 자동으로 설정할 수 있게 해주는 애너테이션.
  • 해당 필드가 명시적으로 설정되지 않을 때, 초기화 표현식으로 제공된 기본값이 사용된다. (참조형 타입의 경우 null)
728x90
반응형