Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.cp_main_be.domain.avatar.avatar.domain.Avatar;
import com.example.cp_main_be.domain.avatar.avatar.domain.repository.AvatarRepository;
import com.example.cp_main_be.domain.garden.garden.domain.Garden;
import com.example.cp_main_be.domain.garden.wateringlog.domain.repository.FriendWateringLogRepository;
import com.example.cp_main_be.domain.home.HomeResponseDto;
import com.example.cp_main_be.domain.member.level.service.LevelService;
Expand All @@ -18,7 +19,9 @@
import com.example.cp_main_be.global.exception.UserNotFoundException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -39,7 +42,10 @@ public class UserService {
private final FollowRepository followRepository;

public void addExperience(Long actorId, int points) {
User user = userRepository.findById(actorId).get();
User user =
userRepository
.findById(actorId)
.orElseThrow(() -> new UserNotFoundException(ErrorCode.USER_NOT_FOUND.getMessage()));
user.addExperience(points);
levelService.checkLevelUp(user);
}
Expand Down Expand Up @@ -112,8 +118,7 @@ public User getCurrentUser() {
}

// Principal이 String(UUID)인 경우 (백업 처리)
if (principal instanceof String) {
String uuidString = (String) principal;
if (principal instanceof String uuidString) {
UUID userUuid = UUID.fromString(uuidString);
return userRepository
.findByUuid(userUuid)
Expand All @@ -140,6 +145,15 @@ public UserProfileResponse getUserProfile(Long currentUserId, Long profileUserId
.findById(profileUserId)
.orElseThrow(() -> new CustomApiException(ErrorCode.NOT_FOUND));

// [추가] 프로필 이미지 URL을 첫 번째 텃밭의 아바타 이미지로 설정
String profileImageUrl =
profileUser.getGardens().stream()
.min(Comparator.comparing(Garden::getSlotNumber)) // 슬롯 번호가 가장 낮은 텃밭 찾기
.map(Garden::getAvatar) // 해당 텃밭의 아바타 가져오기
.filter(Objects::nonNull) // 아바타가 null이 아닌 경우 필터링
.map(avatar -> avatar.getAvatarMaster().getDefaultImageUrl()) // 아바타의 이미지 URL 가져오기
.orElse(profileUser.getProfileImageUrl()); // 텃밭/아바타가 없으면 기존 프로필 이미지 사용

Comment on lines +148 to +156
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

프로필 이미지 URL 계산 시 NPE 가능성(avatarMaster/defaultImageUrl null)

avatar.getAvatarMaster().getDefaultImageUrl() 체인이 null을 전제하지 않습니다. null-safe 필터를 추가해 안전하게 처리하세요. (slotNumber가 null일 수 있다면 Comparator.nullsLast(...)도 고려)

-            .map(avatar -> avatar.getAvatarMaster().getDefaultImageUrl()) // 아바타의 이미지 URL 가져오기
-            .orElse(profileUser.getProfileImageUrl()); // 텃밭/아바타가 없으면 기존 프로필 이미지 사용
+            .map(Avatar::getAvatarMaster) // 마스터 객체 추출
+            .filter(Objects::nonNull) // null 안전
+            .map(master -> master.getDefaultImageUrl()) // 기본 이미지 URL
+            .filter(Objects::nonNull) // null URL 방지
+            .orElse(profileUser.getProfileImageUrl()); // 텃밭/아바타/이미지 없으면 기존 프로필 이미지

추가로(선택): slotNumber null 방지를 위해

-            .min(Comparator.comparing(Garden::getSlotNumber))
+            .min(Comparator.comparing(Garden::getSlotNumber, Comparator.nullsLast(Comparator.naturalOrder())))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// [추가] 프로필 이미지 URL을 첫 번째 텃밭의 아바타 이미지로 설정
String profileImageUrl =
profileUser.getGardens().stream()
.min(Comparator.comparing(Garden::getSlotNumber)) // 슬롯 번호가 가장 낮은 텃밭 찾기
.map(Garden::getAvatar) // 해당 텃밭의 아바타 가져오기
.filter(Objects::nonNull) // 아바타가 null이 아닌 경우 필터링
.map(avatar -> avatar.getAvatarMaster().getDefaultImageUrl()) // 아바타의 이미지 URL 가져오기
.orElse(profileUser.getProfileImageUrl()); // 텃밭/아바타가 없으면 기존 프로필 이미지 사용
// [추가] 프로필 이미지 URL을 첫 번째 텃밭의 아바타 이미지로 설정
String profileImageUrl =
profileUser.getGardens().stream()
.min(Comparator.comparing(
Garden::getSlotNumber,
Comparator.nullsLast(Comparator.naturalOrder())
)) // 슬롯 번호가 가장 낮은 텃밭 찾기 (null-safe)
.map(Garden::getAvatar) // 해당 텃밭의 아바타 가져오기
.filter(Objects::nonNull) // 아바타가 null이 아닌 경우 필터링
- .map(avatar -> avatar.getAvatarMaster().getDefaultImageUrl()) // 아바타의 이미지 URL 가져오기
.map(Avatar::getAvatarMaster) // 마스터 객체 추출
.filter(Objects::nonNull) // null 안전
.map(master -> master.getDefaultImageUrl()) // 기본 이미지 URL
.filter(Objects::nonNull) // null URL 방지
.orElse(profileUser.getProfileImageUrl()); // 텃밭/아바타/이미지 없으면 기존 프로필 이미지
🤖 Prompt for AI Agents
In
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java
around lines 148 to 156, the stream chain
avatar.getAvatarMaster().getDefaultImageUrl() can throw NPE if avatarMaster or
its defaultImageUrl is null (and Comparator may throw if slotNumber is null);
fix by adding null-safe checks: when mapping from Garden to avatar, filter out
null avatars, then filter avatar.getAvatarMaster() != null and
avatar.getAvatarMaster().getDefaultImageUrl() != null before mapping to the URL,
and use Comparator.nullsLast(Comparator.comparing(Garden::getSlotNumber)) (or
Comparator.comparing(g -> g.getSlotNumber(), Comparator.nullsLast(...))) to
handle null slotNumber values so the code safely falls back to
profileUser.getProfileImageUrl().

// 1. 팔로우 상태 확인
// currentUserId -> profileUserId 팔로우 여부
boolean isFollowing = followRepository.existsByFollowerAndFollowing(currentUser, profileUser);
Expand Down Expand Up @@ -202,7 +216,7 @@ public UserProfileResponse getUserProfile(Long currentUserId, Long profileUserId
return UserProfileResponse.builder()
.id(profileUser.getId())
.userNickname(profileUser.getNickname())
.profileImageUrl(profileUser.getProfileImageUrl())
.profileImageUrl(profileImageUrl)
.followStatus(followStatus)
.profileUserLevel(profileUser.getLevel())
.leftWaterCountForOthers(leftWaterCountForOthers)
Expand Down