< 작업 환경 >
IDE: IntelliJ
Spring Boot: 3.4.1
Java: 21
NullPointerException은 우리가 웹 프로젝트를 진행하면서 흔히 마주치는 오류 중 하나입니다. 혼자 스터디 게시판을 만드는 프로젝트를 진행하던 중에 저 또한 여지없이 이 NullPointerException을 만나게 되었습니다. 비록 흔한 오류지만, Spring MVC와 관련된 상황에서 발생했기 때문에 이를 정리해두면 유용할 것 같아 포스팅하게 되었습니다.
아래는 제 로그중 일부입니다.
java.lang.NullPointerException: Cannot invoke "me.cho.snackball.study.domain.Study.getId()" because "study" is null
해당 예외는 아래 코드의 POST 요청을 처리하는 과정에서 발생했습니다.
@PostMapping("/study/{studyId}/update")
public String updateStudy(@CurrentUser User user,
@PathVariable("studyId") Long studyId,
@Valid UpdateStudyForm updateStudyForm,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("studyTags", studyTagService.getStudyTagNames());
model.addAttribute("locations", locationService.getLocationNames());
return "study/updateStudy";
}
studyService.updateStudy(user, updateStudyForm);
return "redirect:/study/" + studyId;
}
@Data
public class UpdateStudyForm {
private Long studyId;
@NotBlank
@Length(max = 30)
private String title;
public UpdateStudyForm(Study study) {
this.studyId = study.getId();
this.title = study.getTitle();
}
}
로그에 따르면 DTO로 쓰려고 만든 UpdateStudyForm 객체의 생성자 첫번재 줄에서 버그가 발생한 것이었습니다. 즉, study.getId()를 호출하는 과정에서 NullPointerException이 터진 것이죠.
이 문제를 해결하려면 '예외가 발생한 지점'이 어디인지에 주목해야 합니다. 예외가 발생한 지점은 바로 Spring MVC가 사용하는 DTO이며, Spring MVC가 DTO를 사용하는 방식을 이해하면 문제의 원인을 찾을 수 있습니다.
<수정된 코드>
@NoArgsConstructor
@Data
public class UpdateStudyForm {
private Long studyId;
@NotBlank
@Length(max = 30)
private String title;
public UpdateStudyForm(Study study) {
this.studyId = study.getId();
this.title = study.getTitle();
}
}
결론 : Spring MVC가 사용하는 DTO에 기본 생성자 만들기
Spring MVC는 @ModelAttribute나 @Valid를 사용할 때, UpdateStudyForm 객체를 생성하여 데이터를 바인딩합니다. 이 과정에서 UpdateStudyForm 클래스의 생성자를 호출합니다.
그런데 코드를 수정하기 전에는 기본 생성자가 없었기 때문에 Spring이 기본 생성자 대신에, 파라미터를 받는 'UpdateStudyForm(Study study)' 생성자를 호출한 것입니다. 그리고 이때 study가 null로 전달되어 NullPointerException 예외가 발생한 것입니다.
따라서 코드에 @NoArgsConstructor를 추가하여 Spring이 기본 생성자로 객체를 생성할 수 있게 해주면 문제가 해결되는 것입니다.