Skip to content

친구 따라가기 기능 추가#105

Merged
jung-min-ju merged 9 commits intodevelopfrom
feat/following-friend
Nov 14, 2025
Merged

친구 따라가기 기능 추가#105
jung-min-ju merged 9 commits intodevelopfrom
feat/following-friend

Conversation

@jung-min-ju
Copy link
Contributor

@jung-min-ju jung-min-ju commented Nov 13, 2025

친구 따라가기 기능 추가


⚙️ 구현 내용

친구 목록에서 "따라가기" 기능 클릭 시, 현재 친구가 속한 게임방의 ID가 반환되는 로직입니다.
에러 목록은 다음과 같습니다.

  • 친구 관계가 아닐 시 -> 현재 피그마에 전체 채팅에서도 우클릭 시 "따라가기" 팝업 발생해 만듦
  • 친구가 게임 방에 속하지 않을 시

📎 Hibernate Proxy와 equals() 비교 실패 이슈 수정

더 자세한 과정은 블로그 에 정리해두었습니다.

이슈 요약

1) 문제 상황

친구 수락 로직에서 같은 User임에도 equals() 비교가 false를 반환하는 문제가 발생함.
기존 equals는 getClass() 비교 + 필드 직접 접근 방식을 사용하고 있었음.

1-1) 친구 수락 로직 복기

A가 B에게 친구 신청을 보냈다고 가정하면,
B가 “친구 수락” 버튼을 눌렀을 때 서버에서는 다음 검증 과정을 수행합니다.

친구 요청에 기록된 수신자(B) 와, 실제로 로그인하여 수락 요청을 보낸 사용자(B) 가 동일한지 확인
이때 사용자 비교는 아래의 equals() 코드로 이루어집니다.

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id != null && id.equals(user.id);
    }

    @Override
    public int hashCode() {
        return (id != null) ? id.hashCode() : 0;
    }
image

기존 equals 함수는 false가 반환되어, 정상 로직 수행이 안됨.

2) 원인 분석

🔥 (원인 1) LAZY 로딩으로 인해 반환된 객체가 “실제 User”가 아니라 “UserProxy”

Hibernate는 LAZY 연관관계 로딩 시 실제 엔티티를 바로 반환하지 않고,
User를 상속한 Proxy 객체를 생성하여 반환함.
Proxy는 실제 필드를 가지고 있지 않고, getter 호출 시 값을 로딩함.

→ 따라서 equals 내부에서 필드를 직접 접근하면 초기화되지 않아 예상과 다르게 동작할 수 있음.

🔥 (원인 2) equals() 호출 주체가 User가 아니라 Proxy였다

디버깅 결과, equals를 호출한 객체는 User.equals()가 아닌
User$HibernateProxy 가 재정의한 equals 메서드였음.

Hibernate 공식 문서 3.24절에서도 다음을 명시함:

  • equals()는 프록시가 전달될 수 있음을 고려해야 함
  • getClass() 비교를 사용하면 Proxy로 인해 오동작함
  • instanceof로 비교해야 함

🔥 (원인 3) equals 내부에서 필드를 직접 접근(id, uuid)

Hibernate 문서에서는 다음을 강조함:

“Access fields of the passed entity via accessor methods.”

Proxy는 실제 필드를 가지고 있지 않고,
값을 필요할 때(getter 호출 시) DB에서 로딩하여 채움.

따라서 필드 직접 접근은 null 또는 잘못된 값이 리턴될 수 있음.
반면 getter를 사용하면 Proxy가 자동으로 초기화되고 올바른 값이 반환됨.


3) 실제 상황 정리

  • toUser: findById로 조회 → 실제 엔티티 반환됨
  • friendRequest.toUser: LAZY ManyToOne → Proxy 객체 반환됨

Proxy 객체는 필드 접근 시 null이 반환될 수 있으므로
friendRequest.toUser.equals(toUser) 비교에서 false가 발생함.


4) 해결 방법

✔ getClass() → instanceof

Proxy는 User의 하위 타입이라 getClass() 비교는 항상 실패 가능함.
문서에서도 instanceof 사용을 권장함.

✔ 필드 접근 → getter 사용

equals에서 user.id 같은 필드 접근 대신 user.getId() 를 사용하면
Proxy가 정상 초기화되므로 비교가 정확하게 동작함.


✔ 최종 결론

문제의 핵심은 Hibernate Proxy 객체와 equals 구현 방식의 충돌이었다.

  • Proxy는 실제 엔티티 필드를 갖고 있지 않음
  • equals 내부에서 필드를 직접 접근하면 null 또는 잘못된 값 반환
  • getClass() 비교도 Proxy에서는 정상 동작하지 않음
  • Hibernate 공식 문서에서 명확히 권장하는 방식:
    • instanceof 타입 비교
    • getter 기반 비교

이 규칙을 적용한 뒤 equals 비교가 정상적으로 통과함.


🧪 테스트 결과

1. 올바른 로직 수행 결과

image

2. 두 사용자가 친구가 아닐 때

image => 400 터지는 에러 403으로 올바르게 터지게 수정했습니다.

3. 친구가 게임방에 속해있지 않을 때

image

Copy link
Contributor

@Uralauah Uralauah left a comment

Choose a reason for hiding this comment

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

확인했습니다.
User 객체 비교에서 문제가 생길 줄은 몰랐네요
또 하나 배워갑니다~

Copy link
Contributor

@brothergiven brothergiven left a comment

Choose a reason for hiding this comment

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

확인했습니다 RoomId만 발견하면 되네요

@jung-min-ju jung-min-ju merged commit d88a06e into develop Nov 14, 2025
1 check passed
@jung-min-ju jung-min-ju deleted the feat/following-friend branch November 14, 2025 09:00
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.

3 participants