【问题标题】:How to convert protocol buffers binary to JSON using the descriptor in Java如何使用 Java 中的描述符将协议缓冲区二进制文件转换为 JSON
【发布时间】:2020-11-24 01:03:16
【问题描述】:

我有一条消息,其字段为“Any”众所周知的类型,可以保存任何类型的序列化 protobuf 消息。

我想将此字段转换为其 json 表示形式。

我知道字段名称是必需的,通常您需要在应用程序中加载生成的类才能使其工作,但我正在寻找一种使用描述符的方法。

首先,我解析描述符:

 FileInputStream descriptorFile = new FileInputStream("/descriptor");
DescriptorProtos.FileDescriptorSet fdp = DescriptorProtos.FileDescriptorSet.parseFrom(descriptorFile);

然后,遍历包含的消息并找到正确的消息(使用“Any”类型的 URL,其中包含包和消息名称。我将其添加到用于格式化 JSON 的 TypeRegistry。

JsonFormat.TypeRegistry.Builder typeRegistryBuilder = JsonFormat.TypeRegistry.newBuilder();

String messageNameFromUrl = member.getAny().getTypeUrl().split("/")[1];

for (DescriptorProtos.FileDescriptorProto file : fdp.getFileList()) {
    for (DescriptorProtos.DescriptorProto dp : file.getMessageTypeList()) {
        if (messageNameFromUrl.equals(String.format("%s.%s", file.getPackage(), dp.getName()))) {

            typeRegistryBuilder.add(dp.getDescriptorForType()); //Doesn't work.
            typeRegistryBuilder.add(MyConcreteGeneratedClass.getDescriptor()); //Works

            System.out.println(JsonFormat.printer().usingTypeRegistry(typeRegistryBuilder.build()).preservingProtoFieldNames().print(member.getAny()));
            return;
        }

    }
}

问题似乎是解析描述符使我可以访问Descriptors.DescriptorProto 对象,但我看不到获取类型注册表所需的Descriptors.Descriptor 对象的方法。我可以使用 getDescriptor() 访问具体类的描述符并且可以正常工作,但是我试图通过从应用程序外部访问预先生成的描述符文件在运行时格式化 JSON,因此我没有可以调用的具体类getDescriptor()

如果我可以使用“Any”字段的类型 URL 来解析 Type 对象并使用它来生成 JSON,那就更好了,因为它似乎也具有为此所需的字段编号和名称过程。

感谢任何帮助,谢谢!

【问题讨论】:

  • 我也尝试使用DynamicMessage 来解析Any,但这也需要传入一个Descriptors.Descriptor,我似乎无法从Descriptors.DescriptorProto 得到它

标签: java protocol-buffers


【解决方案1】:

如果将DescriptorProtos.FileDescriptorProto 转换为Descriptors.FileDescriptor,则后者有一个返回List<Descriptor>getMessageTypes() 方法。

以下是从我正在开发的名为okgrpc 的开源库中提取的 Kotlin 代码的 sn-p。这是在 Java 中创建动态 gRPC 客户端/CLI 的首次尝试。

private fun DescriptorProtos.FileDescriptorProto.resolve(
        index: Map<String, DescriptorProtos.FileDescriptorProto>,
        cache: MutableMap<String, Descriptors.FileDescriptor>
): Descriptors.FileDescriptor {
    if (cache.containsKey(this.name)) return cache[this.name]!!

    return this.dependencyList
        .map { (index[it] ?: error("Unknown dependency: $it")).resolve(index, cache) }
        .let {
            val fd = Descriptors.FileDescriptor.buildFrom(this, *it.toTypedArray())
            cache[fd.name] = fd
            fd
        }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-16
    • 2014-02-21
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 2011-09-20
    相关资源
    最近更新 更多