簡體   English   中英

Golang 將 JSON 解組為 protobuf 生成的結構

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM