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

我想使用客户端应用程序请求 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 main


import (

    "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.RawMessage


goroutine 1 [running]:

main.main()

        /Users/example/go/src/github.com/example/example/main.go:46 +0x1ee


Process finished with exit code 2

有没有办法将此 JSON 解组为Containers?或者,使[]*Container满足proto.Message接口?


阿波罗的战车
浏览 288回答 2
2回答

皈依舞

对于消息容器,即message Containers {    repeated Container containers = 1;}正确的JSON 应如下所示:{   "containers" : [      {        "name": "C1",        "type": "docker"      },      {        "name": "C2",        "type": "docker"      }    ]}如果您无法更改 JSON,那么您可以使用您创建的 funcfunc working(data string) ([]*Container, error) {    var cs []*Container    err := json.Unmarshal([]byte(data), &cs)    // handle the error here    return &Containers{       containers: cs,    }, nil}

互换的青春

您应该使用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)    }
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go