如何将json.RawMessage反序列化为protobuf.Any类型列表?
解决json.RawMessage反序列化为protobuf repeated Any类型的问题
核心原因
google.protobuf.Any的JSON序列化有特定格式要求,必须包含@type字段指定对应proto消息的类型URL,标准库json.Unmarshal无法自动识别并完成Any类型的包装,导致列表为空。
可行解决方案
方案1:借助临时结构体手动解析(适配非标准JSON格式)
如果你的JSON数据未严格遵循protobuf Any的规范(比如缺少@type),可以通过临时结构体先解析数据,再手动包装为Any类型:
- 定义匹配JSON结构的临时结构体:
type TempAnyItem struct { TypeURL string `json:"@type"` // 若JSON无此字段,需手动指定对应类型 Value json.RawMessage `json:"value"` }
- 解析json.RawMessage到临时切片,再逐个转换为Any类型:
// raw 是从数据库获取的json.RawMessage var tempItems []TempAnyItem if err := json.Unmarshal([]byte(raw), &tempItems); err != nil { // 处理解析错误 } // 目标protobuf结构体,对应定义:repeated google.protobuf.Any list = 1; target := &YourProtoStruct{} for _, item := range tempItems { // 根据TypeURL创建对应的具体proto消息实例 var concreteMsg proto.Message switch item.TypeURL { case "type.googleapis.com/your.package.User": concreteMsg = &User{} case "type.googleapis.com/your.package.Order": concreteMsg = &Order{} // 补充其他自定义proto类型分支 default: // 跳过未知类型或处理错误 continue } // 反序列化Value到具体消息 if err := json.Unmarshal(item.Value, concreteMsg); err != nil { continue } // 包装为google.protobuf.Any anyMsg, err := anypb.New(concreteMsg) if err != nil { continue } target.List = append(target.List, anyMsg) }
方案2:使用protojson直接解析(适配标准protobuf JSON格式)
如果你的JSON数据严格遵循protobuf的JSON规范(每个元素都包含@type字段),可以直接使用官方的protojson包完成反序列化:
import "google.golang.org/protobuf/encoding/protojson" // raw 是从数据库获取的json.RawMessage target := &YourProtoStruct{} if err := protojson.Unmarshal([]byte(raw), target); err != nil { // 处理解析错误 }
关键注意事项
- 必须确保JSON数据中每个元素的
@type字段值正确,格式为type.googleapis.com/你的proto包名.消息类型名 - 如果JSON数据原本没有
@type字段,需要补充该字段,或者在代码中手动指定每个元素对应的具体proto类型,否则无法完成Any类型的反序列化
内容的提问来源于stack exchange,提问作者Mido
相关产品推荐
相关产品推荐

