PagingAndSortingRepository - custom pageable response structure

Viewed 2668

Is there a way to simplify the structure returned from this controller:

@GetMapping
public Iterable<Task> getAll(@PathParam("page") int page) {
    Pageable pageable = PageRequest.of(page, 3);

    return taskRepository.findAll(pageable);
}

Right now the body of the response is as follows:

localhost:8080/api/task?page=2

{
    "content": [
        ...
    ],
    "pageable": {
        "sort": {
            "sorted": false,
            "unsorted": true,
            "empty": true
        },
        "offset": 6,
        "pageSize": 3,
        "pageNumber": 2,
        "paged": true,
        "unpaged": false
    },
    "totalElements": 19,
    "last": false,
    "totalPages": 7,
    "number": 2,
    "size": 3,
    "sort": {
        "sorted": false,
        "unsorted": true,
        "empty": true
    },
    "numberOfElements": 3,
    "first": false,
    "empty": false
}

Is there any way to strip down on this data? What if I am not interested in sorting right now and only want to return something like this:

{
    "content": [
        ...
    ],
    "pageable": {
        "pageSize": 3,
        "pageNumber": 2,
        "totalElements": 19,
    },
}

So the current response just has too many properties I don't really need. What is a good way to achieve this? Should I be doing this completely differently if I want to customize it so much?

2 Answers

Another way is to create a custom page class as you want and create from your data and return

@Data
public class CustomPage<T> {
  List<T> content;
  CustomPageable pageable;

  public CustomPage(Page<T> page) {
    this.content = page.getContent();
    this.pageable = new CustomPageable(page.getPageable().getPageNumber(),
        page.getPageable().getPageSize(), page.getTotalElements());
  }

  @Data
  class CustomPageable {
    int pageNumber;
    int pageSize;
    long totalElements;

    public CustomPageable(int pageNumber, int pageSize, long totalElements) {

      this.pageNumber = pageNumber;
      this.pageSize = pageSize;
      this.totalElements = totalElements;
    }
  }
}

And use like this

@GetMapping
public CustomPage<Task> getAll(@PathParam("page") int page) {
    Pageable pageable = PageRequest.of(page, 3);
    return new CustomPage<Task>(taskRepository.findAll(pageable));
}

Note: Here @Data of Lombok used for setter getter etc.

  • It looks like you have to create custom JsonSerializer with @JsonComponent annotation.

  • I will copy the code for reference but you can see it here. PageImpl JSON serialization

    @JsonComponent
    public class PageImplJacksonSerializer extends JsonSerializer<PageImpl<?>> {

    @Override
    public void serialize(PageImpl page, 
                          JsonGenerator jsonGenerator, 
                          SerializerProvider serializerProvider) 
                          throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeObjectField("content", page.getContent());
        jsonGenerator.writeBooleanField("first", page.isFirst());
        jsonGenerator.writeBooleanField("last", page.isLast());
        jsonGenerator.writeNumberField("totalPages", page.getTotalPages());
        jsonGenerator.writeNumberField("totalElements", page.getTotalElements());
        jsonGenerator.writeNumberField("numberOfElements", 
                                       page.getNumberOfElements());

        jsonGenerator.writeNumberField("size", page.getSize());
        jsonGenerator.writeNumberField("number", page.getNumber());
        //sort omitted 

        jsonGenerator.writeEndObject();
      }
    }
Related