[英]Golang unmarshaling JSON to protobuf generated structs
我想使用客戶端應用程序重新發送 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;
}
將此模式與結構一起使用通常是有效的,但由於某些原因,使用這些 proto 定義會導致問題。 下面的代碼演示了一個工作和一個非工作示例。 雖然其中一個版本有效,但我無法使用此解決方案,因為[]*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
接口?
你應該使用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)
}
對於消息容器,即
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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.