PageImpl 직렬화 경고 (ration$PageModule$WarningLoggingModifier ) 로그가 뜰 때

후투티·2025년 4월 29일

잊지마!

목록 보기
16/20

서버를 가동한 후 페이징 처리가 된 기능을 쓰면 딱 한 번 나오는 로그가 있다.

rationPageModulePageModuleWarningLoggingModifier
: Serializing PageImpl instances as-is is not supported, meaning that there is no guarantee about the stability of the resulting JSON structure!
For a stable JSON structure, please use Spring Data's PagedModel
(globally via @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO))
or Spring HATEOAS and Spring Data's PagedResourcesAssembler as documented in https://docs.spring.io/spring-data/commons/reference/repositories/core-extensions.html#core.web.pageables.

이 로그는 PageImpl 객체를 ResponseEntity<Page> 형태로 반환하면, JSON 구조가 불안정할 수 있다고 경고해주는 로그이다.

현재 별 문제는 없이 돌아가고 있지만 뭔가 로그에 찍히면 고치고 싶다.


1. 로그에 적힌 대로 PagedModel과 @EnableSpringDataWebSupport 사용하기

이걸 쓰면 전역 설정이 되어 자동 변환 가능하다
하지만!!!!!
PagedModel을 사용하면 반환형이

{
"content": [데이터들......],
"page": {
"size": 10,
"number": 1,
"totalElements": 228,
"totalPages": 23
}
}

이렇게 고정이 되어버린다.

그런데 우리 서비스는

"content": [],              // 데이터들
"number": 1,                // 현재 페이지 (0부터 시작)
"size": 2,                  // 요청한 페이지 크기
"totalPages": 10,           // 전체 페이지 수
"totalElements": 20,        // 전체 아이템 수
"numberOfElements": 2,      // 현재 페이지에 실제 담긴 아이템 수
"first": false,             // 첫 페이지인지 여부
"last": false,              // 마지막 페이지인지 여부
"empty": false              // 현재 페이지가 비었는지

이런 부가적인 정보들이 더 필요했다.
그래서 이 방법 말고, 다른 방법을 사용해야 했다.


2. PageResponse DTO를 커스텀하여 만들어 사용하기

public class PageResponse<T> {
private List<T> content;
private int number;             // 현재 페이지 번호 (0부터 시작)
private int size;               // 페이지당 아이템 수
private int totalPages;         // 전체 페이지 수
private long totalElements;     // 전체 아이템 수
private int numberOfElements;   // 현재 페이지의 아이템 수
private boolean first;          // 첫 페이지 여부
private boolean last;           // 마지막 페이지 여부
private boolean empty;          // 현재 페이지가 비어있는지 여부

public PageResponse(Page<T> page) {
   this.content = page.getContent();
   this.number = page.getNumber();
   this.size = page.getSize();
   this.totalPages = page.getTotalPages();
   this.totalElements = page.getTotalElements();
   this.numberOfElements = page.getNumberOfElements();
   this.first = page.isFirst();
   this.last = page.isLast();
   this.empty = page.isEmpty();
}
}

여기서
private long totalElements; // 전체 아이템 수
이것만 long 타입인 이유는 Spring Data의 Page 인터페이스에서 정해둔 규칙이기 때문이다.

public interface Page<T> extends Slice<T> {  
int getTotalPages();  
long getTotalElements(); 
}

실제 데이터 개수가 int의 범위를 넘을 수도 있기 때문에 더 큰 범위를 표현할 수 있는 long을 사용하는 것이다.

그리고 컨트롤러에서는

Page<ReviewResponseDTO> reviews = ~~~~~~
return ResponseEntity.ok(new PageResponse<>(reviews));

요렇게 내가 만든 응답 객체인 new PageResponse<>()를 사용해주면
더이상 PageImpl 직렬화 경고 로그가 뜨지 않게 된다!

profile
모르는 건 모른다고 하는 사람

0개의 댓글