如何使用Java中的描述符将协议缓冲区二进制转换为JSON

时间:2019-01-02 22:10:03

标签: java protocol-buffers

我有一条消息,该消息的字段类型为“ 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()

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

感谢您的帮助,谢谢!

1 个答案:

答案 0 :(得分:0)

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

以下是我正在开发的名为okgrpc的开源库中摘录的Kotlin代码片段。这是用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
        }
}