Go语言 Protobuf.Any -从json中解组.RawMessage

qltillow  于 2022-12-07  发布在  Go
关注(0)|答案(1)|浏览(372)

我有来自数据库的数据是json.RawMessage。特定列是jsonb。
我真的找不到一种方法来将数据解组到一个在proto中定义为protobuf的属性中。

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 {
   ...
 }

但是在这个例子中,foo的类型是proto.Message,我不能转换它,因为我有json.RawMessage
有什么办法我可以做到这一点吗?

k3bvogb1

k3bvogb11#

首先,您应该了解DB列中存储了什么。json.RawMessage被简单地定义为type RawMessage []byte(参见文档)。它没有携带足够的信息来回答您的问题。
我将提供一个演示来展示google.protobuf.Any是如何工作的,这将有助于您更好地理解您的问题。

备注

  1. Any用于在消息中嵌入其他类型,因此我在演示中定义了另外两个消息(FooBar)。
    Any消息类型允许您将消息用作嵌入类型,而无需其.proto定义。Any包含任意序列化消息(以字节表示),沿着充当该消息的全局唯一标识符并解析为该消息类型的URL。
    1.实际上,您的问题取决于DB中存储的内容。请参见main.go中的注解。
    演示的文件夹结构:
├── 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\n", 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\n", 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

相关问题