【问题标题】:Protobuf.Any - Unmarshal from a json.RawMessageProtobuf.Any - 从 json.RawMessage 解组
【发布时间】:2022-11-15 14:02:25
【问题描述】:

我有来自数据库的 json.RawMessage 格式的数据。具体的列是jsonb。

我真的找不到一种方法来将数据解组为 proto 上定义为 protobuf.Any 的属性。

repeated google.protobuf.Any list = 1;

当我尝试使用json.Unmarshal() 解组数据库中的数据时,list 为空。文档提到了这样的事情:

foo := &pb.Foo{...}
 any, err := anypb.New(foo)
 if err != nil {
   ...
 }
 ...
 foo := &pb.Foo{}
 if err := any.UnmarshalTo(foo); err != nil {
   ...
 }

但在此示例中,fooproto.Message 类型,我无法转换它,因为我有 json.RawMessage

有什么办法可以做到这一点?

【问题讨论】:

    标签: go protobuf-go


    【解决方案1】:

    首先,您应该了解 DB 列中存储的内容。 json.RawMessage 只是[]byte 的别名(参见the doc)。而且它没有提供足够的信息来回答您的问题。

    我将提供一个演示来展示google.protobuf.Any 是如何工作的,这应该可以帮助您更好地理解您的问题。

    笔记:

    1. Any 用于在消息中嵌入其他类型。所以我在演示中定义了另外两条消息(FooBar)。

      Any 消息类型允许您将消息用作嵌入类型,而无需它们的 .proto 定义。 Any 包含作为字节的任意序列化消息,以及充当该消息类型的全局唯一标识符并解析为该消息类型的 URL。

    2. 实际上,您的问题取决于数据库中存储的内容。请参阅main.go 中的 cmets。

      演示的文件夹结构:

      ├── go.mod
      ├── main.go
      └── pb
          ├── demo.pb.go
          └── demo.proto
      

      go.mod:

      module github.com/ZekeLu/demo
      
      go 1.19
      
      require (
          github.com/golang/protobuf v1.5.2
          google.golang.org/protobuf v1.28.1
      )
      

      pb/demo.proto:

      syntax = "proto3";
      package pb;
      
      import "google/protobuf/any.proto";
      
      option go_package = "github.com/ZekeLu/demo/pb";
      
      message MyMessage {
        repeated google.protobuf.Any list = 1;
      }
      
      message Foo {
        int32 v = 1;
      }
      
      message Bar {
        string v = 1;
      }
      

      main.go

      package main
      
      import (
          "encoding/json"
          "fmt"
      
          "google.golang.org/protobuf/types/known/anypb"
      
          "github.com/ZekeLu/demo/pb"
      )
      
      func main() {
          // If the db stores an instance of pb.Foo, then unmarshal it first.
          buf := json.RawMessage([]byte(`{"v":10}`))
          var foo pb.Foo
          err := json.Unmarshal(buf, &foo)
          if err != nil {
              panic(err)
          }
      
          // And then marshal it into a new Any instance, which can be used to
          // create a slice that can be assigned to pb.MyMessage.List.
          a1, err := anypb.New(&foo)
          if err != nil {
              panic(err)
          }
      
          bar := &pb.Bar{V: "10"}
          a2, err := anypb.New(bar)
          if err != nil {
              panic(err)
          }
      
          // Initialize the List field.
          m := pb.MyMessage{List: []*anypb.Any{a1, a2}}
      
          buf, err = json.Marshal(&m)
          if err != nil {
              panic(err)
          }
          fmt.Printf("%s
      ", buf)
          // Output: {"list":[{"type_url":"type.googleapis.com/pb.Foo","value":"CAo="},{"type_url":"type.googleapis.com/pb.Bar","value":"CgIxMA=="}]}
      
          // If the db stores the output above, it can be unmarshal directly
          var m2 pb.MyMessage
          err = json.Unmarshal(buf, &m2)
          if err != nil {
              panic(err)
          }
      
          fmt.Printf("%v
      ", m2.List)
          // Output: [[type.googleapis.com/pb.Foo]:{v:10} [type.googleapis.com/pb.Bar]:{v:"10"}]
      }
      

      运行演示的步骤:

      $ protoc --proto_path=pb --go_out=pb --go_opt=paths=source_relative demo.proto
      $ go mod tidy
      $ go run main.go
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      • 1970-01-01
      • 2020-02-09
      • 1970-01-01
      相关资源
      最近更新 更多