Spring Boot
Page Deserialization
PageImpl
Constructor
Java

Spring Boot Page Deserialization - PageImpl No constructor

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

PageImpl deserialization problems usually happen because Jackson wants a default constructor or a constructor it knows how to call, but Spring's PageImpl was not designed as a plain DTO for arbitrary JSON reconstruction. The class needs page content plus paging metadata, so a trivial no-arg constructor is not the normal usage pattern. The practical fix is usually to deserialize into a custom page wrapper, a DTO, or a subclass that gives Jackson a usable constructor.

Why PageImpl Is Awkward for Jackson

A PageImpl represents more than just a list of items. It also includes:

  • page number
  • page size
  • total element count
  • sorting and paging metadata

Because of that, it is not a simple bean with a default constructor and a few setters. Jackson often needs extra help to turn JSON back into a PageImpl<T>.

A Common Wrapper Solution

A practical pattern is to create a small subclass with a Jackson-friendly constructor.

java
1import com.fasterxml.jackson.annotation.JsonCreator;
2import com.fasterxml.jackson.annotation.JsonProperty;
3import org.springframework.data.domain.PageImpl;
4import org.springframework.data.domain.PageRequest;
5
6import java.util.List;
7
8public class RestPageImpl<T> extends PageImpl<T> {
9
10    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
11    public RestPageImpl(
12            @JsonProperty("content") List<T> content,
13            @JsonProperty("number") int number,
14            @JsonProperty("size") int size,
15            @JsonProperty("totalElements") long totalElements) {
16        super(content, PageRequest.of(number, size), totalElements);
17    }
18
19    public RestPageImpl() {
20        super(List.of());
21    }
22}

This gives Jackson a constructor it can actually use.

Using the Wrapper in a Client Call

If you are consuming a paged Spring endpoint with RestTemplate, deserialize into the wrapper rather than directly into PageImpl.

java
1import org.springframework.core.ParameterizedTypeReference;
2import org.springframework.http.HttpMethod;
3import org.springframework.http.ResponseEntity;
4import org.springframework.web.client.RestTemplate;
5
6RestTemplate restTemplate = new RestTemplate();
7
8ResponseEntity<RestPageImpl<MyDto>> response = restTemplate.exchange(
9        "http://localhost:8080/items",
10        HttpMethod.GET,
11        null,
12        new ParameterizedTypeReference<RestPageImpl<MyDto>>() {}
13);
14
15RestPageImpl<MyDto> page = response.getBody();

This is a common solution when one Spring service is calling another.

Another Option: Avoid Page at the API Boundary

Sometimes the better answer is not to deserialize PageImpl at all. Instead, return a custom DTO that contains exactly the fields your API clients need.

java
1import java.util.List;
2
3public record PageResponse<T>(
4        List<T> content,
5        int page,
6        int size,
7        long totalElements
8) {}

This is often easier to evolve and easier to deserialize than exposing framework types directly across service boundaries.

Why a No-Arg Constructor Alone Is Not the Whole Story

People often focus on the missing default constructor, but the deeper issue is that pagination metadata has to map correctly too. Even if a default constructor exists, Jackson still needs to know how to populate all the necessary fields in a meaningful way.

So the real fix is not merely "make Jackson stop complaining." The real fix is to make the serialized format and the target type line up clearly.

When This Appears Most Often

This problem commonly shows up in:

  • 'RestTemplate clients'
  • Feign or custom HTTP client deserialization
  • tests that deserialize paged JSON responses manually
  • service-to-service calls where Page is used as a transport type

Inside a single Spring MVC controller returning JSON outward, you often never notice the issue because serialization works fine. The pain appears during deserialization on the receiving side.

Common Pitfalls

  • Trying to deserialize directly into Page<T> even though it is an interface.
  • Focusing only on the missing no-arg constructor instead of the full metadata mapping problem.
  • Exposing framework pagination types directly over service boundaries when a dedicated DTO would be clearer.
  • Forgetting generic type information during deserialization, which causes content items to become loosely typed maps.
  • Solving the issue in one client with custom code but leaving other clients to repeat the same workaround.

Summary

  • 'PageImpl is awkward to deserialize because it is not a trivial DTO with a simple constructor story.'
  • A Jackson-friendly subclass such as RestPageImpl<T> is a common practical solution.
  • Another strong option is to return a custom page DTO instead of PageImpl at the API boundary.
  • The issue is about both constructor availability and correct paging metadata mapping.
  • Serialization usually works fine; deserialization is where the mismatch becomes visible.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.