Skip to content

Kotlinx.serialization not used for serializing Page<T> and ignores all configurationΒ #28389

@Nek-12

Description

@Nek-12

Affects:
3.0.0-M1

When returning object from a controller method using @ResponseBody, and if the returned type is Page<T> where T is a class marked as @kotlinx.serialization.Serializable, kotlinx.serialization is not used, it is unclear what exactly is used, and, assuming it's Jackson that is used, all configuration, all annotations and other properties are ignored.

I'm using custom InstantSerializer that serializes dates as strings for Kotlinx.serialization.

My POJO is annotated as follows

@file:UseSerializers(InstantSerializer::class, UUIDSerializer::class)

@kotlinx.serialization.Serializable
data class GetProductResponse(
    /* ... */
    @JsonSerialize(using = JacksonInstantSerializer::class)
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    val createdAt: Instant,
    val id: UUID,
)

Returning List or of this pojo returns string for createdAt field: "createdAt": "2022-03-29T20:19:30.304149Z"
However, returning Page the field is : "createdAt": 1650109008.203314000. This breaks FE and introduces inconsistency.

I must note that I specifically would like to use strings to serialize dates.

I tried to work around this issue by providing custom Jackson configuration:

  • Using code:
  @Bean
  fun jacksonObjectMapper(): ObjectMapper = ObjectMapper().apply {
      registerModule(JavaTimeModule())
      disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  }
  • Using application.properties:
spring.mvc.converters.preferred-json-mapper=kotlinx.serialization
spring.jackson.serialization.write_dates_as_timestamps=false
  • Using annotations:
 @JsonSerialize(using = JacksonInstantSerializer::class)
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    val createdAt: Instant,

None of the above methods worked, and I'm unable to achieve the desired behavior.

My Controller method is as follows:

@GetMapping("/")
    fun getAll(pageable: Pageable, @RequestBody request: GetProductsFilteredRequest?): Page<GetProductResponse> {
        return productRepository.findFiltered(
            pageable,
           /* ... */
        ).map { it.toResponse() }
    }

Condition evaluations report is as follows:

   JacksonAutoConfiguration.JacksonObjectMapperConfiguration#jacksonObjectMapper:
      Did not match:
         - @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found beans of type 'com.fasterxml.jackson.databind.ObjectMapper' jacksonObjectMapper (OnBeanCondition)

   JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration:
      Did not match:
         - @ConditionalOnProperty (spring.mvc.converters.preferred-json-mapper=jackson) found different value in property 'spring.mvc.converters.preferred-json-mapper' (OnPropertyCondition)
      Matched:
         - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)

   JacksonHttpMessageConvertersConfiguration.MappingJackson2XmlHttpMessageConverterConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'com.fasterxml.jackson.dataformat.xml.XmlMapper' (OnClassCondition)

UPDATE:
Registering kotlin module for ObjectMapper:

@Bean
    fun jacksonObjectMapper(): ObjectMapper = ObjectMapper().apply {
        registerModule(JavaTimeModule())
        registerKotlinModule()
        disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
    }

Allows to apply a workaround by using Jackson configuration alongside kotlinx.serialization configuration (only for annotation, other properties are still ignored)

The bug is still valid because kotlinx.serialization is not used for Page content.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: invalidAn issue that we don't feel is validtheme: kotlinAn issue related to Kotlin support

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions