簡體   English   中英

Spring webtestclient 將日期序列化為時間戳而不是日期

[英]Spring webtestclient serializes dates to timestamps instead of dates

我正在嘗試檢查從 webtestclient 返回的數據是否與我的預期相同。 但是,當我將 Jackson 應用於 webtestclient 編解碼器時,來自用戶數據 class 的 ZonedDateTime 不僅顯示為日期,還顯示為時間戳。 示例: 2021-12-09T16:39:43.225207700+01:00轉換為1639064383.225207700而我預計不會有任何變化。 有人可以解釋我做錯了什么。 (在測試之外調用此端點時使用此 jackson 配置給出的日期不是時間戳)

WebTestClientUtil:

object WebTestClientUtil {
    fun webTestClient(routerFunction: RouterFunction<ServerResponse>): WebTestClient {
        return WebTestClient
            .bindToRouterFunction(routerFunction)
            .configureClient()
            .codecs { configurer: ClientCodecConfigurer ->
                configurer.defaultCodecs().jackson2JsonEncoder(Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON))
                configurer.defaultCodecs().jackson2JsonDecoder(Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON))
            }
            .build()
    }
}

測試用例:

@Test
fun `get user when given correct data`() {
    val user = GlobalMocks.mockedUser
    coEvery { userRepository.getUserWithData(any()) } returns user

    val result = webTestClient.get()
        .uri("/api/v1/user/${user.userId}")
        .exchange()
        .expectStatus().is2xxSuccessful
        .expectBody<Result>().returnResult().responseBody?.payload


    assertEquals(user, result)
}

data class Result(
    val payload: User
)

Jackson 配置:

class JacksonConfig {
    companion object {
        val serializationDateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXX")
        val deserializationDateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm[:ss][XXX][X]")
        val objectMapper = jacksonObjectMapper().applyDefaultSettings()

        private fun ObjectMapper.applyDefaultSettings() =
            apply {
                disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
                disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

                enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
                setSerializationInclusion(JsonInclude.Include.NON_NULL)

                registerModule(Jdk8Module())
                registerModule(ParameterNamesModule())
                registerModule(JsonComponentModule())
                registerModule(
                    JavaTimeModule().apply {
                        addSerializer(ZonedDateTime::class.java, ZonedDateTimeSerializer(serializationDateFormat))
                        addDeserializer(ZonedDateTime::class.java, ZonedDateTimeDeserializer())
                    }
                )
            }
    }

    class ZonedDateTimeDeserializer : JsonDeserializer<ZonedDateTime>() {
        override fun deserialize(jsonParser: JsonParser, deserializationContext: DeserializationContext): ZonedDateTime {
            val epochTime = jsonParser.text.toLongOrNull()
            return if (epochTime != null) {
                ZonedDateTime.ofInstant(
                    Instant.ofEpochSecond(epochTime),
                    currentZone
                )
            } else {
                ZonedDateTime.parse(jsonParser.text, deserializationDateFormat)
            }
        }
    }
}

編輯:還發現了這個問題,這讓我認為它可能與bindToRouterFunction

您需要定義一個ObjectMapper bean,以便不使用自動配置的 bean:

@Configuration(proxyBeanMethods = false)
class JacksonConfiguration {

    companion object {
        val serializationDateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXX")
        val deserializationDateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm[:ss][XXX][X]")
    }

    @Bean
    fun objectMapper() = jacksonObjectMapper().applyDefaultSettings ()

    private fun ObjectMapper.applyDefaultSettings() =
        apply {
            disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
            disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

            enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
            setSerializationInclusion(JsonInclude.Include.NON_NULL)

            registerModule(Jdk8Module())
            registerModule(ParameterNamesModule())
            registerModule(JsonComponentModule())
            registerModule(
                JavaTimeModule().apply {
                    addSerializer(ZonedDateTime::class.java, ZonedDateTimeSerializer(serializationDateFormat))
                    addDeserializer(ZonedDateTime::class.java, ZonedDateTimeDeserializer())
                }
            )
        }

    class ZonedDateTimeDeserializer : JsonDeserializer<ZonedDateTime>() {
        override fun deserialize(jsonParser: JsonParser, deserializationContext: DeserializationContext): ZonedDateTime {
            val epochTime = jsonParser.text.toLongOrNull()
            return if (epochTime != null) {
                ZonedDateTime.ofInstant(
                    Instant.ofEpochSecond(epochTime),
                    currentZone
                )
            } else {
                ZonedDateTime.parse(jsonParser.text, deserializationDateFormat)
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM