문제 정의
캘린더 일정 조회 API 호출 시 다음과 같은 오류가 발생했습니다:
Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]
이는 JPA Entity를 JSON으로 직렬화하는 과정에서 발생한 문제로, Calendar 엔티티와 User 엔티티 간의 양방향 참조로 인한 순환 참조(Circular Reference) 이슈입니다.
문제 발생 원인
- Calendar 엔티티가 User 엔티티를 참조
- JPA의 지연 로딩(LAZY Loading)으로 인해 프록시 객체가 생성됨
- 이 프록시 객체를 JSON으로 직렬화하려 할 때 Jackson 라이브러리가 처리하지 못함
시도한 해결 방법들
1. @JsonIgnore 어노테이션 사용
@Entity
public class Calendar {
@ManyToOne
@JsonIgnore
private User user;
}
- 문제점: User 정보가 완전히 누락되어 클라이언트에서 필요한 사용자 정보를 얻을 수 없음
2. @JsonManagedReference, @JsonBackReference 사용
@Entity
public class Calendar {
@ManyToOne
@JsonManagedReference
private User user;
}
- 문제점: 복잡한 객체 그래프에서 예측하기 어려운 동작 발생
최종 해결 방법: DTO 패턴 적용
1. DTO 클래스 생성
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CalendarDTO {
private Long id;
private String employeeId;
private String title;
private LocalDateTime start;
private LocalDateTime end;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// Entity -> DTO 변환 메서드
public static CalendarDTO from(Calendar entity) {
return CalendarDTO.builder()
.id(entity.getId())
.employeeId(entity.getUser().getEmployeeId())
.title(entity.getTitle())
.start(entity.getStart())
.end(entity.getEnd())
.createdAt(entity.getCreatedAt())
.updatedAt(entity.getUpdatedAt())
.build();
}
// DTO -> Entity 변환 메서드
public Calendar toEntity(User user) {
Calendar calendar = new Calendar();
calendar.setTitle(this.title);
calendar.setStart(this.start);
calendar.setEnd(this.end);
calendar.setUser(user);
return calendar;
}
}
2. Controller에서 DTO 사용
@RestController
@RequestMapping("/api/calendar")
@RequiredArgsConstructor
public class CalendarController {
@GetMapping
public ResponseEntity<List<CalendarDTO>> getUserEvents(@RequestHeader("X-User-Id") String employeeId) {
return ResponseEntity.ok(service.getUserEvents(employeeId).stream()
.map(CalendarDTO::from)
.collect(Collectors.toList()));
}
@PostMapping
public ResponseEntity<CalendarDTO> createEvent(
@RequestHeader("X-User-Id") String employeeId,
@RequestBody CalendarDTO calendarDTO) {
Calendar savedCalendar = service.createEvent(employeeId, calendarDTO);
return ResponseEntity.ok(CalendarDTO.from(savedCalendar));
}
}
해결 결과
-
순환 참조 문제 해결: Entity 간의 순환 참조 문제가 DTO를 통해 깔끔하게 해결됨
-
데이터 전송 최적화:
- 필요한 데이터만 클라이언트로 전송
- User 엔티티의 민감한 정보(비밀번호 등) 노출 방지
-
명확한 API 계약:
- API 응답 형식이 DTO를 통해 명확하게 정의됨
- 프론트엔드와의 인터페이스가 더 안정적으로 변경
-
성능 향상:
- 불필요한 데이터 직렬화/역직렬화 과정 제거
- 네트워크 전송 데이터량 감소
추가 고려사항
- Validation: DTO 클래스에 검증 로직 추가 검토
- Mapping Library: 복잡한 엔티티-DTO 변환 시 MapStruct 등 매핑 라이브러리 도입 고려
- API 문서화: Swagger/OpenAPI 문서에 DTO 스키마 추가
이러한 해결 방법을 통해 안정적이고 효율적인 API 응답 처리가 가능해졌습니다.
문제 정의
캘린더 일정 조회 API 호출 시 다음과 같은 오류가 발생했습니다:
이는 JPA Entity를 JSON으로 직렬화하는 과정에서 발생한 문제로, Calendar 엔티티와 User 엔티티 간의 양방향 참조로 인한 순환 참조(Circular Reference) 이슈입니다.
문제 발생 원인
시도한 해결 방법들
1. @JsonIgnore 어노테이션 사용
2. @JsonManagedReference, @JsonBackReference 사용
최종 해결 방법: DTO 패턴 적용
1. DTO 클래스 생성
2. Controller에서 DTO 사용
해결 결과
순환 참조 문제 해결: Entity 간의 순환 참조 문제가 DTO를 통해 깔끔하게 해결됨
데이터 전송 최적화:
명확한 API 계약:
성능 향상:
추가 고려사항
이러한 해결 방법을 통해 안정적이고 효율적인 API 응답 처리가 가능해졌습니다.