生成的OpenAPI Go客户端日期反序列化异常问题排查
问题根源:日期格式与OpenAPI Schema不匹配
这不是Go客户端的bug,而是服务端返回的日期格式和OpenAPI Schema声明的格式不一致导致的解析失败:
- 你的Kotlin代码中使用
java.sql.Date类型,Spring默认会将其序列化为yyyy-MM-dd纯日期格式(如"2022-10-28")。 - 但生成的OpenAPI Schema中,
transactionDate和postedDate的format被标记为date-time,这要求返回ISO 8601带时间的格式(如"2022-10-28T00:00:00Z")。 - 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
相关产品推荐
相关产品推荐

