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;
}

将此模式与structs一起正常使用是有效的,但是由于某些原因,使用这些原型定义会导致问题。下面的代码演示了一个有效的和无效的示例。尽管其中一种版本有效,但由于[]*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"
  }
]`

    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)
    }
,

对于消息容器,即

<ConfigurationType>DynamicLibrary</ConfigurationType>

正确 JSON应该类似于:

message Containers {
    repeated Container containers = 1;
}

如果您无法更改JSON,则可以利用已创建的功能

{
   "containers" : [
      {
        "name": "C1","type": "docker"
      }
    ]
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...