如何将第三方库的CredentialResult结构体转为指定JSON格式?
问题:将第三方库的CredentialResult结构体转换为指定格式JSON
第三方库定义的Golang结构体如下:
type Credentials struct { TmpSecretID string `json:"TmpSecretId,omitempty"` TmpSecretKey string `json:"TmpSecretKey,omitempty"` SessionToken string `json:"Token,omitempty"` } type CredentialError struct { Code string `json:"Code,omitempty"` Message string `json:"Message,omitempty"` RequestId string `json:"RequestId,omitempty"` } type CredentialResult struct { Credentials *Credentials `json:"Credentials,omitempty"` ExpiredTime int `json:"ExpiredTime,omitempty"` Expiration string `json:"Expiration,omitempty"` StartTime int `json:"StartTime,omitempty"` RequestId string `json:"RequestId,omitempty"` Error *CredentialError `json:"Error,omitempty"` }
需要转换为如下格式的JSON:
{ "credentials":{ "tmpSecretId":"", "tmpSecretKey":"", "sessionToken":"" }, "requestId":"", "expiration":"", "startTime":1, "expiredTime":1 }
最优实现方案
方法一:自定义映射结构体(推荐)
这种方式直观易懂,代码可维护性高,是最常用的最优方案。核心思路是定义一个与目标JSON结构完全匹配的本地结构体,手动将第三方结构体的字段值映射过去,再序列化。
package main import ( "encoding/json" "fmt" ) // 第三方库结构体(实际使用时直接引用第三方库即可) type Credentials struct { TmpSecretID string `json:"TmpSecretId,omitempty"` TmpSecretKey string `json:"TmpSecretKey,omitempty"` SessionToken string `json:"Token,omitempty"` } type CredentialResult struct { Credentials *Credentials `json:"Credentials,omitempty"` ExpiredTime int `json:"ExpiredTime,omitempty"` Expiration string `json:"Expiration,omitempty"` StartTime int `json:"StartTime,omitempty"` RequestId string `json:"RequestId,omitempty"` } // 定义与目标JSON匹配的本地结构体 type TargetCredentialResult struct { Credentials struct { TmpSecretID string `json:"tmpSecretId"` TmpSecretKey string `json:"tmpSecretKey"` SessionToken string `json:"sessionToken"` } `json:"credentials"` RequestId string `json:"requestId"` Expiration string `json:"expiration"` StartTime int `json:"startTime"` ExpiredTime int `json:"expiredTime"` } // 转换函数:将第三方结构体转为本地目标结构体 func ConvertToTargetFormat(src *CredentialResult) (*TargetCredentialResult, error) { if src == nil { return nil, fmt.Errorf("source CredentialResult cannot be nil") } target := &TargetCredentialResult{ RequestId: src.RequestId, Expiration: src.Expiration, StartTime: src.StartTime, ExpiredTime: src.ExpiredTime, } // 处理嵌套的Credentials字段 if src.Credentials != nil { target.Credentials.TmpSecretID = src.Credentials.TmpSecretID target.Credentials.TmpSecretKey = src.Credentials.TmpSecretKey target.Credentials.SessionToken = src.Credentials.SessionToken } return target, nil } func main() { // 模拟从第三方库获取的CredentialResult实例 srcResult := &CredentialResult{ Credentials: &Credentials{ TmpSecretID: "test-id", TmpSecretKey: "test-key", SessionToken: "test-token", }, RequestId: "req-123", Expiration: "2024-12-31T12:00:00Z", StartTime: 1735689600, ExpiredTime: 1735693200, } // 转换并序列化 targetResult, err := ConvertToTargetFormat(srcResult) if err != nil { fmt.Printf("convert error: %v\n", err) return } jsonBytes, err := json.MarshalIndent(targetResult, "", " ") if err != nil { fmt.Printf("marshal error: %v\n", err) return } fmt.Println(string(jsonBytes)) }
优点:
- 代码逻辑清晰,可读性强,后续字段修改时易维护
- 序列化性能高,无需额外的JSON处理逻辑
- 可灵活处理字段默认值、空值等特殊情况
方法二:自定义MarshalJSON方法
如果不想额外定义结构体,可以给CredentialResult类型实现json.Marshaler接口,直接控制序列化后的JSON格式。
package main import ( "encoding/json" "fmt" ) // 第三方库结构体(实际使用时直接引用第三方库即可) type Credentials struct { TmpSecretID string `json:"TmpSecretId,omitempty"` TmpSecretKey string `json:"TmpSecretKey,omitempty"` SessionToken string `json:"Token,omitempty"` } type CredentialResult struct { Credentials *Credentials `json:"Credentials,omitempty"` ExpiredTime int `json:"ExpiredTime,omitempty"` Expiration string `json:"Expiration,omitempty"` StartTime int `json:"StartTime,omitempty"` RequestId string `json:"RequestId,omitempty"` } // 给CredentialResult实现自定义MarshalJSON方法 func (cr *CredentialResult) MarshalJSON() ([]byte, error) { if cr == nil { return []byte("null"), nil } // 定义临时结构体匹配目标JSON格式 type tmpCredentials struct { TmpSecretID string `json:"tmpSecretId"` TmpSecretKey string `json:"tmpSecretKey"` SessionToken string `json:"sessionToken"` } tmpStruct := struct { Credentials *tmpCredentials `json:"credentials"` RequestId string `json:"requestId"` Expiration string `json:"expiration"` StartTime int `json:"startTime"` ExpiredTime int `json:"expiredTime"` }{ RequestId: cr.RequestId, Expiration: cr.Expiration, StartTime: cr.StartTime, ExpiredTime: cr.ExpiredTime, } if cr.Credentials != nil { tmpStruct.Credentials = &tmpCredentials{ TmpSecretID: cr.Credentials.TmpSecretID, TmpSecretKey: cr.Credentials.TmpSecretKey, SessionToken: cr.Credentials.SessionToken, } } return json.Marshal(tmpStruct) } func main() { // 模拟第三方库返回的实例 srcResult := &CredentialResult{ Credentials: &Credentials{ TmpSecretID: "test-id", TmpSecretKey: "test-key", SessionToken: "test-token", }, RequestId: "req-123", Expiration: "2024-12-31T12:00:00Z", StartTime: 1735689600, ExpiredTime: 1735693200, } // 直接序列化原结构体 jsonBytes, err := json.MarshalIndent(srcResult, "", " ") if err != nil { fmt.Printf("marshal error: %v\n", err) return } fmt.Println(string(jsonBytes)) }
适用场景:
- 临时转换场景,不想额外定义结构体
- 第三方结构体字段固定,后续不会频繁变动
方案选择建议
如果是长期使用的业务场景,优先选择方法一,因为代码的可维护性和可读性更好;如果是临时的一次性转换,可以使用方法二简化代码。
内容的提问来源于stack exchange,提问作者OneQ
相关产品推荐
相关产品推荐

