为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 将 JSON 解组为 protobuf 生成的结构

Golang 将 JSON 解组为 protobuf 生成的结构

Go
阿波罗的战车 2022-06-27 16:27:06
我想使用客户端应用程序请求 JSON 响应并将此响应解组为结构。为了确保结构在使用此包的所有客户端应用程序中保持相同,我想将 JSON 响应定义为 protobuf 消息。我很难将 JSON 解组为 protobuf 生成的结构。我有以下 JSON 数据:[  {    "name": "C1",    "type": "docker"  },  {    "name": "C2",    "type": "docker"  }]我已经像这样建模了我的 protobuf 定义:syntax = "proto3";package main;message Container {    string name = 1;    string type = 2;}message Containers {    repeated Container containers = 1;}将此模式与结构一起使用通常可以工作,但由于某种原因,使用这些原型定义会导致问题。下面的代码演示了一个工作和一个非工作示例。尽管其中一个版本有效,但我无法使用此解决方案,因为[]*Container不满足proto.Message接口。package mainimport (    "encoding/json"    "fmt"    "strings"    "github.com/gogo/protobuf/jsonpb")func working(data string) ([]*Container, error) {    var cs []*Container    return cs, json.Unmarshal([]byte(data), &cs)}func notWorking(data string) (*Containers, error) {    c := &Containers{}    jsm := jsonpb.Unmarshaler{}    if err := jsm.Unmarshal(strings.NewReader(data), c); err != nil {        return nil, err    }    return c, nil}func main() {    data := `[  {    "name": "C1",    "type": "docker"  },  {    "name": "C2",    "type": "docker"  }]`    w, err := working(data)    if err != nil {        panic(err)    }    fmt.Print(w)    nw, err := notWorking(data)    if err != nil {        panic(err)    }    fmt.Print(nw.Containers)}运行它会给出以下输出:[name:"C1" type:"docker"  name:"C2" type:"docker" ]panic: json: cannot unmarshal array into Go value of type map[string]json.RawMessagegoroutine 1 [running]:main.main()        /Users/example/go/src/github.com/example/example/main.go:46 +0x1eeProcess finished with exit code 2有没有办法将此 JSON 解组为Containers?或者,使[]*Container满足proto.Message接口?
查看完整描述

2 回答

?
皈依舞

TA贡献1851条经验 获得超3个赞

对于消息容器,即


message Containers {

    repeated Container containers = 1;

}

正确的JSON 应如下所示:


{

   "containers" : [

      {

        "name": "C1",

        "type": "docker"

      },

      {

        "name": "C2",

        "type": "docker"

      }

    ]

}

如果您无法更改 JSON,那么您可以使用您创建的 func


func working(data string) ([]*Container, error) {

    var cs []*Container

    err := json.Unmarshal([]byte(data), &cs)

    // handle the error here

    return &Containers{

       containers: cs,

    }, nil

}


查看完整回答
反对 回复 2022-06-27
?
互换的青春

TA贡献1797条经验 获得超6个赞

您应该使用NewDecoder将数据传输到jsonDecoder然后遍历数组。代码是这样的


 func main() {

        data := `

    [

      {

        "name": "C1",

        "type": "docker"

      },

      {

        "name": "C2",

        "type": "docker"

      }

    ]`

        jsonDecoder := json.NewDecoder(strings.NewReader(data))

        _, err := jsonDecoder.Token()

        if err != nil {

            log.Fatal(err)

        }

        var protoMessages []*pb.Container

        for jsonDecoder.More() {

            protoMessage := pb.Container{}

            err := jsonpb.UnmarshalNext(jsonDecoder, &protoMessage)

            if err != nil {

                log.Fatal(err)

            }

            protoMessages = append(protoMessages, &protoMessage)

        }

        fmt.Println("%s", protoMessages)

    }


查看完整回答
反对 回复 2022-06-27
  • 2 回答
  • 0 关注
  • 284 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信