Skip to content

Add Kotlinx Serialization for Page #3548

Open

Description

@hmzgtl16

When using kotlinx.serialization as the JSON message converter in a Spring Boot web application, returning a Spring Data Page<T> from a @RestController results in an HttpMessageNotWritableException.
Because kotlinx.serialization is strictly opt-in, it fails when encountering PageImpl since it lacks the @Serializable annotation and a registered custom serializer.

The request fails with HTTP 500 and the following exception:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write kotlinx.serialization.json.JsonImpl@44a50e85: Serializer for subclass 'PageImpl' is not found in the polymorphic scope of 'Page'.
Check if class with serial name 'PageImpl' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'PageImpl' has to be '@Serializable', and the base class 'Page' has to be sealed and '@Serializable'.

Spring WebMvc should ideally provide a built-in mechanism or registered KSerializer to handle standard Spring wrapper classes like Page and PageImpl when kotlinx.serialization is the active message converter, similar to how Jackson handles it.

Activity

  1. changed the title [-]Kotlinx Serialization fails to serialize Spring Data PageImpl[/-] [+]Add Kotlinx Serialization for `Page`[/+] on Sep 28, 2026
  2. Kanish2002 commented on Oct 12, 2026

    @Kanish2002

    I reproduced the converter failure in an isolated JVM test (Spring Framework 7.0.0, Spring Data Commons 4.0.0, Kotlin 2.2.0, kotlinx.serialization 1.9.0). Four converter-level checks passed:

    • With a permissive type predicate and no custom module, canWrite(Page<String>, PageImpl.class, application/json) returns true, but write throws HttpMessageNotWritableException naming the missing PageImpl serializer. Eligibility alone therefore does not detect this failure.
    • Registering a generic contextual serializer for Page fixes serializer lookup, but the default Framework 7 converter still rejects Page<String> because neither the wrapper nor its element type has @Serializable.
    • With that contextual provider and a predicate restricted to the declared Page type, the converter successfully writes a runtime PageImpl using the element serializer resolved from Page<String>. The experiment used a small diagnostic JSON shape, not a proposed wire format.
    • An output-only KSerializer whose deserialize throws still makes canRead return true, and reading then fails. An outbound-only design needs to account for this.

    For implementation, could we use the existing stable PagedModel representation (content plus page: {size, number, totalElements, totalPages}) rather than expose PageImpl internals? A generic contextual provider could take the element serializer from its type arguments. Converter integration would also need a narrowly scoped eligibility policy, and tests should cover both Page<@Serializable DTO> and Page<String>, nullable DTO properties, empty pages, declared PageImpl versus Page, and the intended read behavior.

    Following the contribution guidelines' discussion-first requirement for API additions, I'm raising these design points before an upstream API patch. Would opt-in module registration plus documented converter configuration be an acceptable initial scope, or is automatic Spring Data web registration intended?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions