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

生成的OpenAPI Go客户端日期反序列化异常问题排查

问题根源:日期格式与OpenAPI Schema不匹配

这不是Go客户端的bug,而是服务端返回的日期格式和OpenAPI Schema声明的格式不一致导致的解析失败:

  1. 你的Kotlin代码中使用java.sql.Date类型,Spring默认会将其序列化为yyyy-MM-dd纯日期格式(如"2022-10-28")。
  2. 但生成的OpenAPI Schema中,transactionDate和postedDate的format被标记为date-time,这要求返回ISO 8601带时间的格式(如"2022-10-28T00:00:00Z")。
  3. OpenAPI Generator根据date-time格式生成了Go的time.Time类型,并默认用date-time的解析规则处理返回值,纯日期字符串自然无法匹配带T的格式规则,最终抛出解析错误。

解决方案

推荐选择以下两种规范的修复方式,避免后续维护问题:

方案1:修改服务端,让日期序列化符合date-time格式

在Kotlin的Transaction日期字段上添加@JsonFormat注解,强制输出date-time格式:

import com.fasterxml.jackson.annotation.JsonFormat

data class Transaction(
        val id: Long,
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
        val transactionDate: Date,
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
        val postedDate: Date?,
        val amount: BigDecimal,
        val category: Category,
        val merchant: Merchant,
        val merchantDescription: String?
)

修改后Spring会返回"2022-10-28T00:00:00Z"格式的日期,Go客户端可直接解析。

方案2:修正OpenAPI Schema,将日期格式改为date

如果业务场景只需要日期(不需要时间),应将Schema中的date-time改为date,同时让Spring的OpenAPI生成器正确识别java.sql.Date对应date类型:

步骤1:给Kotlin字段添加@Schema注解

import io.swagger.v3.oas.annotations.media.Schema

data class Transaction(
        val id: Long,
        @Schema(type = "string", format = "date")
        val transactionDate: Date,
        @Schema(type = "string", format = "date")
        val postedDate: Date?,
        val amount: BigDecimal,
        val category: Category,
        val merchant: Merchant,
        val merchantDescription: String?
)

步骤2:重新生成Go客户端

此时生成的GoTransaction结构体中,日期字段会变为string类型(或适配date格式的自定义类型),可直接解析yyyy-MM-dd格式的字符串。


临时方案:自定义Go客户端的日期解析逻辑

如果暂时无法修改服务端或Schema,可手动修改生成的Go代码,添加自定义JSON反序列化逻辑:

import (
    "time"
    "encoding/json"
    "fmt"
)

const dateFormat = "2006-01-02"

func (t *Transaction) UnmarshalJSON(data []byte) error {
    type TempTransaction struct {
        Id                  *int64     `json:"id,omitempty"`
        TransactionDate     *string    `json:"transactionDate,omitempty"`
        PostedDate          *string    `json:"postedDate,omitempty"`
        Amount              *float32   `json:"amount,omitempty"`
        Category            *Category  `json:"category,omitempty"`
        Merchant            *Merchant  `json:"merchant,omitempty"`
        MerchantDescription *string    `json:"merchantDescription,omitempty"`
    }

    var temp TempTransaction
    if err := json.Unmarshal(data, &temp); err != nil {
        return err
    }

    if temp.TransactionDate != nil {
        parsedDate, err := time.Parse(dateFormat, *temp.TransactionDate)
        if err != nil {
            return fmt.Errorf("invalid transactionDate: %v", err)
        }
        t.TransactionDate = &parsedDate
    }
    if temp.PostedDate != nil {
        parsedDate, err := time.Parse(dateFormat, *temp.PostedDate)
        if err != nil {
            return fmt.Errorf("invalid postedDate: %v", err)
        }
        t.PostedDate = &parsedDate
    }

    t.Id = temp.Id
    t.Amount = temp.Amount
    t.Category = temp.Category
    t.Merchant = temp.Merchant
    t.MerchantDescription = temp.MerchantDescription

    return nil
}

注意:此方法每次重新生成Go客户端都需要重复修改,仅作为临时应急方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:25:23