-
Notifications
You must be signed in to change notification settings - Fork 704
Description
Motivation
Currently, spring.data.web.pageable.serialization-mode=via_dto uses the built-in PagedModel class
for JSON serialization. There is no way to provide a custom DTO globally, which limits projects
that need different field names or additional metadata like hasNext/hasPrevious.
Additionally, even when spring.data.web.pageable.one-indexed-parameters=true is set,
the returned number field in PagedModel still starts from 0 instead of 1.
It is unclear whether this is intentional or a bug. This makes it difficult to have
a consistent 1-based pagination model for both input and output without manually wrapping
the Page in a custom DTO in every controller.
Proposal
Add support for configuring a custom DTO class for serialization, for example:
spring.data.web.pageable.serialization-mode=via_dto
spring.data.web.pageable.dto-class=com.example.PagedModelpackage com.example;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.jspecify.annotations.NonNull;
import org.springframework.data.domain.Page;
import org.springframework.util.Assert;
import java.util.List;
@JsonPropertyOrder({"content", "page"})
public record PagedModel<T>(Page<@NonNull T> page) {
public PagedModel(Page<@NonNull T> page) {
Assert.notNull(page, "Page must not be null");
this.page = page;
}
@JsonProperty("content")
public List<T> getContent() {
return page.getContent();
}
@JsonProperty("page")
public PageMetadata getMetadata() {
return new PageMetadata(page.getSize(), page.getNumber() + 1, page.getTotalElements(),
page.getTotalPages(),
!page.isFirst(),
!page.isLast());
}
public record PageMetadata(long size, long number, long totalElements, long totalPages, boolean hasNext, boolean hasPrevious) {
public PageMetadata {
Assert.isTrue(size > -1, "Size must not be negative!");
Assert.isTrue(number > -1, "Number must not be negative!");
Assert.isTrue(totalElements > -1, "Total elements must not be negative!");
Assert.isTrue(totalPages > -1, "Total pages must not be negative!");
Assert.notNull(hasNext, "hasNext must not be null");
Assert.notNull(hasPrevious, "hasPrevious must not be null");
}
}
public static <T> PagedModel<T> of(Page<@NonNull T> page) {
Assert.notNull(page, "Page must not be null");
return new PagedModel<>(page);
}
}