Go语言自定义JSON反序列化:status字段为对象或整数的处理问题
问题分析与解决方案
原代码核心问题
- 递归调用死循环:
Status的自定义UnmarshalJSON中,反序列化对象时直接使用Status类型,会再次触发自身的UnmarshalJSON方法,导致无限递归栈溢出。 - 未处理根节点字段映射:格式二中的
title、detail是与status同级的根节点字段,原代码未将这些字段合并到Status结构体中,不符合统一结构体的要求。
修复后的完整代码
package main import ( "encoding/json" "errors" ) type ShipmentOrderResponse struct { Status Status `json:"status"` Items *[]Item `json:"items,omitempty"` } type Status struct { Title string `json:"title,omitempty"` Code int `json:"statusCode,omitempty"` Instance string `json:"instance,omitempty"` Detail string `json:"detail,omitempty"` } type Item struct { PropertyPath string `json:"propertyPath"` Message string `json:"message"` } // 修复Status的UnmarshalJSON,避免递归 func (s *Status) UnmarshalJSON(d []byte) error { // 先尝试反序列化为整数类型(格式二的status字段) var code int if err := json.Unmarshal(d, &code); err == nil { s.Code = code return nil } // 再尝试反序列化为对象类型(格式一的status字段),用匿名结构体绕过自定义Unmarshal var obj struct { Title string `json:"title"` Code int `json:"statusCode"` Detail string `json:"detail"` Instance string `json:"instance,omitempty"` } if err := json.Unmarshal(d, &obj); err != nil { return err } s.Title = obj.Title s.Code = obj.Code s.Detail = obj.Detail s.Instance = obj.Instance return nil } // 给ShipmentOrderResponse添加自定义Unmarshal,处理两种响应格式 func (sor *ShipmentOrderResponse) UnmarshalJSON(d []byte) error { // 尝试匹配格式一:status为对象,包含items字段 type FormatOne struct { Status Status `json:"status"` Items *[]Item `json:"items,omitempty"` } var formatOne FormatOne if err := json.Unmarshal(d, &formatOne); err == nil { sor.Status = formatOne.Status sor.Items = formatOne.Items return nil } // 尝试匹配格式二:status为整数,根节点包含title、detail type FormatTwo struct { Status int `json:"status"` Title string `json:"title"` Detail string `json:"detail"` } var formatTwo FormatTwo if err := json.Unmarshal(d, &formatTwo); err == nil { sor.Status.Code = formatTwo.Status sor.Status.Title = formatTwo.Title sor.Status.Detail = formatTwo.Detail sor.Items = nil return nil } return errors.New("invalid response format: neither format matched") }
关键修复说明
- 避免递归:在
Status的反序列化中,使用匿名结构体来解析对象类型的status,绕过自定义的UnmarshalJSON方法,彻底解决递归死循环问题。 - 统一字段映射:通过
ShipmentOrderResponse的自定义UnmarshalJSON,分别适配两种响应格式:- 格式一直接映射到目标结构体;
- 格式二将根节点的
title、detail合并到Status字段中,实现两种格式的结构统一。
- 简化结构体:移除原
ShipmentOrderResponse中的Title、Detail字段,所有状态信息统一存储在Status结构体中,符合目标结构体设计。
内容的提问来源于stack exchange,提问作者Maciej Czarnota
相关产品推荐
相关产品推荐

