You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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?
Activity
[-]Kotlinx Serialization fails to serialize Spring Data PageImpl[/-][+]Add Kotlinx Serialization for `Page`[/+]Kanish2002 commentedon Oct 12, 2026
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:
canWrite(Page<String>, PageImpl.class, application/json)returns true, butwritethrowsHttpMessageNotWritableExceptionnaming the missingPageImplserializer. Eligibility alone therefore does not detect this failure.Pagefixes serializer lookup, but the default Framework 7 converter still rejectsPage<String>because neither the wrapper nor its element type has@Serializable.Pagetype, the converter successfully writes a runtimePageImplusing the element serializer resolved fromPage<String>. The experiment used a small diagnostic JSON shape, not a proposed wire format.KSerializerwhosedeserializethrows still makescanReadreturn true, and reading then fails. An outbound-only design needs to account for this.For implementation, could we use the existing stable
PagedModelrepresentation (contentpluspage: {size, number, totalElements, totalPages}) rather than exposePageImplinternals? 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 bothPage<@Serializable DTO>andPage<String>, nullable DTO properties, empty pages, declaredPageImplversusPage, 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?