【问题标题】:how to store protocol buffer's "oneof" field with json如何用 json 存储协议缓冲区的“oneof”字段
【发布时间】:2020-12-12 03:51:00
【问题描述】:

我想将我的 protobuf 的消息对象转换为 json 以保存/加载到 redis。 但是 oneof 字段没有按预期工作。

  • test.proto

一个简单的例子。

syntax = "proto3";

message example {
    oneof test {
        bool one = 1;
        bool two = 2;
    }
}
  • 生成文件

如何将 protobuf 代码构建到 golang 中。

.PHONY: proto

proto:
    protoc -Iproto/ -I/usr/local/include \
        -I$(GOPATH)/src \
        -I$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/ \
        --go_out=plugins=grpc:proto \
        proto/test.proto 
  • main.go

我如何编组/解组我的示例对象。

package main

import (
    "encoding/json"
    "fmt"
    pb "test/proto"
)

func main() {
    fmt.Println()

    obj := pb.Example{Test: &pb.Example_One{true}}
    fmt.Println(obj)
    fmt.Println("before one: ", obj.GetOne())
    fmt.Println("before two: ", obj.GetTwo())

    jsonData, _ := json.Marshal(obj)
    fmt.Println(string(jsonData))
    fmt.Println("-----")

    obj2 := pb.Example{}
    _ = json.Unmarshal(jsonData, &obj2)
    fmt.Println(obj2)
    fmt.Println("after one: ", obj2.GetOne())
    fmt.Println("after two: ", obj2.GetTwo())
}

那么,结果是

$ go run main.go

{{{} [] [] <nil>} 0 [] 0xc0000141a0}
before one:  true
before two:  false
{"Test":{"One":true}}
-----
{{{} [] [] <nil>} 0 [] <nil>}
after one:  false
after two:  false

有人知道原因吗?

【问题讨论】:

  • 使用protojson package:“这个包产生的输出与标准的'encoding/json'包不同,后者不能在协议缓冲区消息上正确运行。”

标签: json go protocol-buffers


【解决方案1】:

感谢彼得,我可以将我的消息编码为 json。

protojson document

  • 我的协议环境
// versions:
//  protoc-gen-go v1.25.0-devel
//  protoc        v3.6.

我的答案代码

package main

import (
    "fmt"
    pb "test/proto"

    "google.golang.org/protobuf/encoding/protojson"
)

func main() {
    obj := pb.Example{Test: &pb.Example_One{true}}
    fmt.Println(obj)
    fmt.Println("before one: ", obj.GetOne())
    fmt.Println("before two: ", obj.GetTwo())

    jsonData, _ := protojson.Marshal(&obj)
    fmt.Println(string(jsonData))
    fmt.Println("-----")

    obj2 := pb.Example{}
    _ = protojson.Unmarshal(jsonData, &obj2)
    fmt.Println(obj2)
    fmt.Println("after one: ", obj2.GetOne())
    fmt.Println("after two: ", obj2.GetTwo())
}

结果

$ go run main.go
{{{} [] [] <nil>} 0 [] 0xc0000141cc}
before one:  true
before two:  false
{"one":true}
-----
{{{} [] [] 0xc0001203c0} 0 [] 0xc000014253}
after one:  true
after two:  false

【讨论】:

  • 请注意:生成的 json 不会生成原始问题中的 Test 标记。
  • 是的,但仍然认为 正确的表示;如果你真的想要那个Test 标签,你应该以不同的方式定义原始消息。例如,oneofs 不应该影响二进制格式的序列化;它们也不应该在 json 中影响它们。
猜你喜欢
  • 2016-12-19
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-08
  • 2011-09-18
  • 2011-05-10
  • 2014-09-13
相关资源
最近更新 更多