Skip to content

fix: 리뷰v2 - menu 리뷰 작성시 menuLike가 null일때 발생하는 NPE을 방지해요#352

Open
HI-JIN2 wants to merge 2 commits intodevelopfrom
fix/npe-reviewv2
Open

fix: 리뷰v2 - menu 리뷰 작성시 menuLike가 null일때 발생하는 NPE을 방지해요#352
HI-JIN2 wants to merge 2 commits intodevelopfrom
fix/npe-reviewv2

Conversation

@HI-JIN2
Copy link
Copy Markdown
Member

@HI-JIN2 HI-JIN2 commented Mar 26, 2026

#️⃣ Issue Number

resolved #349

원인: /v2/reviews/menu에서 CreateMenuReviewRequestV2.menuLike를 필수로 가정하고 request.getMenuLike().getMenuId()를 바로 호출해서, 요청이 menuLike: null로 오면 NPE로 500이 발생했습니다.

좀 더 풀어서 설명하자면,
CreateMenuReviewRequestV2의 경우 menuLike(meunid, islike)이외에 별도의 menuid를 받지 않습니다(중복된다 판단하여 별도로 추가하지 않았습니다)
그렇기에 menu에 대한 리뷰를 작성하는데, menuId가 없어서 NPE이 발생했습니다.

📝 요약(Summary)

해결: 현재 발생한 500 NPE를 400대 에러로 방어하며, 추가적으로 NPE를 방지하기 위해 다음과 같은 조건을 추가했습니다.

  • CreateMenuReviewRequestV2.rating, CreateMenuReviewRequestV2.menuLike에 @NotNull 추가, menuLike에 @Valid 추가
  • MenuLikeRequest.menuId에 @NotNull 추가
  • ReviewServiceV2.createMenuReview()에서 menuLike/menuId null이면 BaseException(FAILED_VALIDATION)으로 처리
  • isLike가 null이어도 NPE 안 나도록 Boolean.TRUE.equals(...)로 기본값 false 처리
  • imageUrls/menuLikes가 null이어도 NPE 안 나도록 Collections.emptyList()로 방어(식단리뷰/리뷰수정도 같이 보강)

💬 공유사항 to 리뷰어

not null이 과하지 않은지 점검 부탁드립니다.
저의 생각은

  • CreateMenuReviewRequestV2.menuLike @NotNull
    이 엔드포인트(/v2/reviews/menu)는 메뉴를 식별할 값이 menuLike.menuId밖에 없어서, menuLike가 null이면 애초에 처리 불가능 (이 PR 핵심입니다)
  • MenuLikeRequest.menuId @NotNull
    menuId가 없으면 islike가 true든 false든 메뉴리뷰든 의미가 성립하지 않습니다. (다만 CreateMealReviewRequest.menuLikes는 필드에 @Valid가 없어서 “검증 어노테이션만으로”는 리스트 원소 검증이 안 걸릴 수 있는데, 서비스에서 이미 null 방어를 추가해둔 상태라 동작상 문제는 없습니다.
  • CreateMenuReviewRequestV2.rating @NotNull
    현재 기획단에서 0점 리뷰를 금지하고 있습니다.
    기존에는 @Min/@max만 있어서 rating:null도 검증을 통과할 수 있었습니다.(Bean Validation은 null이면 통과)
    NotNull을 통해 해당 정책을 명시적으로 400으로 바꿨습니다.

꼭 전체적인 이해 후에 approved 부탁드립니다! 질문/의견 있으면 편하게 남겨주세요

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

HI-JIN2 added 2 commits March 27, 2026 02:01
menuLike/menuId 누락 시 FAILED_VALIDATION으로 실패시키고, isLike/imageUrls/menuLikes null도 안전하게 처리해 NPE를 방지합니다.
CreateMenuReviewRequestV2의 rating/menuLike와 MenuLikeRequest의 menuId에 검증을 추가해 잘못된 요청을 조기에 400으로 처리합니다.
@HI-JIN2 HI-JIN2 self-assigned this Mar 26, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

본 PR은 메뉴 리뷰 작성 시 발생하는 NullPointerException(NPE) 문제를 해결하기 위해 DTO 유효성 검증을 강화하고 서비스 계층의 방어적 코드를 보강하는 작업을 수행했습니다. 이를 통해 잘못된 요청에 대해 명확한 400 에러를 반환하고, 시스템의 안정성을 높였습니다.

Highlights

  • NPE 방지 및 유효성 검증 강화: CreateMenuReviewRequestV2와 MenuLikeRequest에 @NotNull@Valid 어노테이션을 추가하여 필수 입력값을 강제하고, 서비스 계층에서 null 체크를 통해 500 에러 대신 400 에러를 반환하도록 개선했습니다.
  • 안전한 데이터 처리: 리뷰 작성 및 수정 로직에서 imageUrls와 menuLikes가 null일 경우를 대비해 Collections.emptyList()를 사용하고, isLike 필드에 Boolean.TRUE.equals()를 적용하여 NPE 발생 가능성을 제거했습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


메뉴 리뷰 작성 시에, 널 값이 들어오면 멈추네. 어노테이션 꼼꼼히 붙여서, 안전한 코드로 거듭나네.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이번 풀 리퀘스트는 리뷰 생성 및 수정 시 데이터 무결성을 보장하기 위해 DTO에 유효성 검증 어노테이션(@NotNull, @Valid 등)을 추가하고, 서비스 레이어에서 발생할 수 있는 null 참조를 방지하기 위해 Optional 처리 및 수동 검증 로직을 도입했습니다. 리뷰어는 DTO 수준에서 이미 유효성 검사가 수행되므로 서비스 레이어 내의 중복된 null 체크 로직을 제거하여 코드를 최적화할 것을 권장했습니다.

Comment on lines +117 to +119
if (menuLike == null || menuLike.getMenuId() == null) {
throw new BaseException(FAILED_VALIDATION);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

FIX ME: CreateMenuReviewRequestV2.menuLike와 MenuLikeRequest.menuId에 @NotNull@Valid 어노테이션이 적용되어 있으므로, 이 서비스 메서드에 도달하기 전에 유효성 검사가 완료되어야 합니다. 따라서 이 null 체크는 중복될 수 있습니다. DTO 유효성 검사에 의존하여 이 로직을 제거하는 것을 고려해 보세요.

List<MenuLikeRequest> menuLikeRequests = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());

Map<Menu, Boolean> menuLikes = menuLikeRequests.stream()
.filter(Objects::nonNull)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createMealReview(87줄)에서는 menuLike == null이면 FAILED_VALIDATION으로 예외를 던지는데, 여기서는 .filter(Objects::nonNull)로 조용히 무시합니다. 같은 MenuLikeRequest 리스트인데 처리 방식이 다르면 클라이언트 입장에서 혼란스러울 수 있으니, 여기도 null이면 FAILED_VALIDATION으로 통일하는 게 일관성 있을 것 같습니다...!

@Max(5)
private Integer rating;

@NotNull
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 PR에서 CreateMenuReviewRequestV2에는 rating에 @NotNull, menuLike에 @NotNull @Valid를 추가했는데, 같은 도메인의 CreateMealReviewRequest에는 rating(25줄)에 @NotNull이 없고, menuLikes(26줄)에 @Valid도 없습니당

서비스 레이어에서 null 방어를 해둬서 동작상 문제는 없지만, DTO validation도 맞춰주면 더 일관성이 있을 것 같아보여용...!
따로 별도 PR로 해도 괜찮을 것 같아요

Comment on lines +117 to +119
if (menuLike == null || menuLike.getMenuId() == null) {
throw new BaseException(FAILED_VALIDATION);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateMenuReviewRequestV2에 @NotNull @Valid menuLike를 달았고, 컨트롤러에서 @Valid @RequestBody로 받고 있으므로, 이 null 체크는 Bean Validation을 통과한 뒤에는 도달할 수 없네용
방어적 프로그래밍으로 남겨두는 건 OK인데 흠 createMealReview(87줄)쪽은 DTO에 @Valid가 없어서 실제로 유효한 방어임니다
이 차이를 구분할 수 있도록 간단한 주석이 있으면 좋겠습니다!

Menu menu = menuRepository.findById(menuLike.getMenuId())
.orElseThrow(() -> new BaseException(NOT_FOUND_MENU));
review.addReviewMenuLike(menu, menuLike.getIsLike());
boolean isLike = Boolean.TRUE.equals(menuLike.getIsLike());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boolean.TRUE.equals(menuLike.getIsLike())로 null일 때 false(싫어요)로 처리하는 건 깔끔합니당
다만 "좋아요/싫어요를 선택하지 않음"이 별도 상태라면, null을 false로 치환하는 건 데이터 왜곡이 될 수 있으니 비즈니스 로직 확인하면 좋겟네여!
125번째 줄 416번째 줄도 동일한 포인트입니당

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: createMenuReviewRequestV2 - NullPointerException

2 participants