You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit2+Gson自定义ZonedDateTime序列化器失效问题求助

Retrofit2 + Gson 中 ZonedDateTime 自定义序列化器失效问题解决

问题原因

Gson 的 JsonSerializer 仅负责JSON请求体的序列化,并不处理 @Query 这类查询参数的字符串转换。Retrofit 处理查询参数时,默认逻辑是直接调用参数的 toString() 方法,或者使用内置的 StringConverter,不会触发你注册的 Gson 自定义序列化器。

你的 LocalDate 序列化器能生效,大概率是因为 Gson 和 Retrofit 都没有默认处理 LocalDate 的逻辑,因此 fallback 到了你的自定义序列化器;而 ZonedDateTime 存在默认的字符串转换逻辑,所以没走到你的序列化代码。

解决方案

方案1:自定义 StringConverter 专门处理 ZonedDateTime

创建一个 Converter.Factory,直接将 ZonedDateTime 转换为目标格式的字符串,优先于 Gson 处理查询参数:

class ZonedDateTimeConverterFactory : Converter.Factory() {
    override fun stringConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<*, String>? {
        return if (type == ZonedDateTime::class.java) {
            Converter<ZonedDateTime, String> { value ->
                DateTimeFormatter.ISO_INSTANT.format(value)
            }
        } else {
            super.stringConverter(type, annotations, retrofit)
        }
    }
}

构建 Retrofit 时将这个 Converter 放在 GsonConverterFactory 前面:

Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(ZonedDateTimeConverterFactory())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

方案2:让 Gson 处理所有查询参数的序列化

自定义 Converter.Factory,利用已配置好的 Gson 来序列化所有查询参数,这样你的自定义序列化器就能被触发:

class GsonQueryConverterFactory(private val gson: Gson) : Converter.Factory() {
    override fun stringConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<*, String>? {
        val adapter = gson.getAdapter(TypeToken.get(type))
        return Converter<Any, String> { value ->
            // 去掉Gson序列化后自动添加的引号
            adapter.toJson(value).replace("\"", "")
        }
    }
}

构建 Retrofit 时添加这个 Factory,并确保 Gson 已注册你的序列化器:

val gson = GsonBuilder()
    .registerTypeAdapter(ZonedDateTime::class.java, ZonedDateTimeSerializer())
    .registerTypeAdapter(LocalDate::class.java, LocalDateSerializer())
    .create()

Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonQueryConverterFactory(gson))
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

优化序列化器代码(可选)

将序列化器的参数名改为更贴合的名称,提升可读性:

class ZonedDateTimeSerializer : JsonSerializer<ZonedDateTime?> {
    override fun serialize(
        zonedDateTime: ZonedDateTime?,
        srcType: Type?,
        context: JsonSerializationContext?
    ): JsonElement {
        val formatter = DateTimeFormatter.ISO_INSTANT
        return JsonPrimitive(formatter.format(zonedDateTime))
    }
}

内容的提问来源于stack exchange,提问作者tasjapr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 01:04:55