本文介绍了无需预编译 Go 代码即可将 protobuf 序列化消息转换为 JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将 protobuf 序列化消息转换为人类可读的 JSON 格式.我面临的主要问题是我需要在不事先将 proto 描述符编译为 Go 代码的情况下执行此操作.我可以在运行时访问 .proto 文件,但不能在编译时访问.

I want to convert protobuf serialized messages into a human readable JSON format. The major problem I face is that I need to do this without compiling the proto descriptor into Go code beforehand. I have access to the .proto files at runtime, but not at compile time.

我的印象是新的 Protobuf API v2 (https://github.com/protocolbuffers/protobuf-go) 支持动态反序列化(请参阅包 types/dynamicpb),但我显然无法弄清楚如何使用它:

I had the impression that the new Protobuf API v2 (https://github.com/protocolbuffers/protobuf-go) supports dynamic deserialization (see package types/dynamicpb), but I couldn't figure out how to use it apparently:

func readDynamically(in []byte) {
    // How do I load the required descriptor (for NewMessage()) from my `addressbook.proto` file?)
    descriptor := ??

    msg := dynamicpb.NewMessage(descriptor)
    err := protojson.Unmarshal(in, msg)
    if err != nil {
        panic(err)
    }
}

上面的代码注释了我的问题:如何从 .proto 文件中获取 dynamicpb.NewMessage() 所需的描述符?

Above code is annotated with my problem: How can I get the required descriptor for the dynamicpb.NewMessage() from a .proto file?

推荐答案

应该像这样使用 dynamicpb 包.

Should work like this with the dynamicpb package.

func readDynamically(in []byte) {
    registry, err := createProtoRegistry(".", "addressbook.proto")
    if err != nil {
        panic(err)
    }

    desc, err := registry.FindFileByPath("addressbook.proto")
    if err != nil {
        panic(err)
    }
    fd := desc.Messages()
    addressBook := fd.ByName("AddressBook")

    msg := dynamicpb.NewMessage(addressBook)
    err = proto.Unmarshal(in, msg)
    jsonBytes, err := protojson.Marshal(msg)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(jsonBytes))
    if err != nil {
        panic(err)
    }
}

func createProtoRegistry(srcDir string, filename string) (*protoregistry.Files, error) {
    // Create descriptors using the protoc binary.
    // Imported dependencies are included so that the descriptors are self-contained.
    tmpFile := filename + "-tmp.pb"
    cmd := exec.Command("./protoc/protoc",
        "--include_imports",
        "--descriptor_set_out=" + tmpFile,
        "-I"+srcDir,
        path.Join(srcDir, filename))

    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err := cmd.Run()
    if err != nil {
        return nil, err
    }
    defer os.Remove(tmpFile)

    marshalledDescriptorSet, err := ioutil.ReadFile(tmpFile)
    if err != nil {
        return nil, err
    }
    descriptorSet := descriptorpb.FileDescriptorSet{}
    err = proto.Unmarshal(marshalledDescriptorSet, &descriptorSet)
    if err != nil {
        return nil, err
    }

    files, err := protodesc.NewFiles(&descriptorSet)
    if err != nil {
        return nil, err
    }

    return files, nil
}

这篇关于无需预编译 Go 代码即可将 protobuf 序列化消息转换为 JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 19:44