问题描述
我想随客户端应用程序一起请求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"
}
]
}