이번 강의(18강)에서는 드디어 RsData를 제네릭(Generic) 으로 바꾸면서
이전 강의에서 임시로 사용했던 Object 타입을 제거한다.
이걸로 인해:
RsData 하나로 통일 가능즉, 응답 구조가 “진짜 실무형”으로 완성되는 단계였다.
17강에서는 RsData가 이렇게 생겼다.
public record RsData(String resultCode, String msg, Object data) {
}
이 구조도 JSON 응답은 잘 되지만, 문제는 명확했다.
data에 무엇이 들어가는지 코드만 보고 알기 어려움그래서 강의에서도 “Object는 지양하는 게 좋다”는 방향성을 잡았다.
18강에서 RsData는 이렇게 변경된다.
package com.back.global.rsData;
public record RsData<T>(String resultCode, String msg, T data) {
}
이제 data는 Object가 아니라 T(타입 파라미터) 로 결정된다.
RsData<PostDto> → data는 PostDto만 가능RsData<PostCommentDto> → data는 PostCommentDto만 가능글 삭제 API는 다음과 같이 변경된다.
@GetMapping("/{id}/delete")
@Transactional
public RsData<PostDto> delete(@PathVariable int id) {
Post post = postService.findById(id).get();
postService.delete(post);
return new RsData<>(
"200-1",
"%d번 글이 삭제되었습니다.".formatted(id),
new PostDto(post)
);
}
여기서 중요한 포인트:
RsData<PostDto> 로 명확해짐new RsData<>(...) 처럼 생성자에서는 <>만 써도 됨PostDto가 자동으로 결정된다.강의에서 언급된 포인트가 이거였다.
컨트롤러 메서드 반환 타입에
RsData<PostDto>가 아니라RsData라고만 써도 동작은 한다.
이게 가능한 이유는 단순하다.
RsData<T>의 T 정보가 사라짐RsData(raw type)로 써도 자바는 컴파일이 되긴 함하지만 강의에서 강조한 것처럼:
RsData(raw type)는 사실상RsData<Object>처럼 되어버린다.
즉, 동작은 해도…
👉 그래서 지양하는 게 좋다.
댓글 삭제도 마찬가지로 제네릭을 적용한다.
@GetMapping("/{id}/delete")
@Transactional
public RsData<PostCommentDto> delete(
@PathVariable int postId,
@PathVariable int id
) {
Post post = postService.findById(postId).get();
PostComment postComment = post.findCommentById(id).get();
postService.deleteComment(post, postComment);
return new RsData<>(
"200-1",
"%d번 댓글이 삭제되었습니다.".formatted(id),
new PostCommentDto(postComment)
);
}
이제 댓글 삭제 응답도:
PostCommentDto로 고정응답 스펙이 코드만 봐도 완전히 명확해졌다.
이번 강의 흐름을 한 줄로 정리하면 이렇다.
즉, “왜 제네릭이 필요한지”를
강의를 따라가며 자연스럽게 납득시키는 흐름이었다.
Object data는 편하지만 타입 안정성이 없다RsData<T> 제네릭을 적용하면:RsData만 쓰는(raw type) 방식은 사실상 RsData<Object>와 같아서 지양해야 한다18강은 “공통 응답 RsData”를
진짜 범용 + 타입 안전한 형태로 완성한 강의였다.