协议缓冲区:如何在 Java 中解析 .proto 文件

问题描述 投票:0回答:4

我正在尝试动态解析 Java 中给定的 .proto 文件以解码 Protobuf 编码的二进制文件。

我有以下解析方法,其中“proto”字符串包含.proto文件的内容:

public static Descriptors.FileDescriptor parseProto (String proto) throws InvalidProtocolBufferException, Descriptors.DescriptorValidationException {
        DescriptorProtos.FileDescriptorProto descriptorProto = DescriptorProtos.FileDescriptorProto.parseFrom(proto.getBytes());
        return Descriptors.FileDescriptor.buildFrom(descriptorProto, null);
}

但是,在执行时,前面的方法会抛出异常,并显示消息“协议消息标记的线路类型无效。”。我使用来自 Google 的示例 .proto 文件,所以我猜它是有效的:https://github.com/google/protobuf/blob/master/examples/addressbook.proto

这是堆栈跟踪:

15:43:24.707 [pool-1-thread-1] ERROR com.github.whiver.nifi.processor.ProtobufDecoderProcessor - ProtobufDecoderProcessor[id=42c8ab94-2d8a-491b-bd99-b4451d127ae0] Protocol message tag had invalid wire type.
com.google.protobuf.InvalidProtocolBufferException$InvalidWireTypeException: Protocol message tag had invalid wire type.
    at com.google.protobuf.InvalidProtocolBufferException.invalidWireType(InvalidProtocolBufferException.java:115)
    at com.google.protobuf.UnknownFieldSet$Builder.mergeFieldFrom(UnknownFieldSet.java:551)
    at com.google.protobuf.GeneratedMessageV3.parseUnknownField(GeneratedMessageV3.java:293)
    at com.google.protobuf.DescriptorProtos$FileDescriptorSet.<init>(DescriptorProtos.java:88)
    at com.google.protobuf.DescriptorProtos$FileDescriptorSet.<init>(DescriptorProtos.java:53)
    at com.google.protobuf.DescriptorProtos$FileDescriptorSet$1.parsePartialFrom(DescriptorProtos.java:773)
    at com.google.protobuf.DescriptorProtos$FileDescriptorSet$1.parsePartialFrom(DescriptorProtos.java:768)
    at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:163)
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:197)
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:209)
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:214)
    at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49)
    at com.google.protobuf.DescriptorProtos$FileDescriptorSet.parseFrom(DescriptorProtos.java:260)
    at com.github.whiver.nifi.parser.SchemaParser.parseProto(SchemaParser.java:9)
    at com.github.whiver.nifi.processor.ProtobufDecoderProcessor.lambda$onTrigger$0(ProtobufDecoderProcessor.java:103)
    at org.apache.nifi.util.MockProcessSession.write(MockProcessSession.java:895)
    at org.apache.nifi.util.MockProcessSession.write(MockProcessSession.java:62)
    at com.github.whiver.nifi.processor.ProtobufDecoderProcessor.onTrigger(ProtobufDecoderProcessor.java:100)
    at org.apache.nifi.processor.AbstractProcessor.onTrigger(AbstractProcessor.java:27)
    at org.apache.nifi.util.StandardProcessorTestRunner$RunProcessor.call(StandardProcessorTestRunner.java:251)
    at org.apache.nifi.util.StandardProcessorTestRunner$RunProcessor.call(StandardProcessorTestRunner.java:245)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

有什么想法吗? 谢谢!

java protocol-buffers protobuf-java
4个回答
10
投票

看起来您正在尝试使用

FileDescriptorSet.parseFrom
来填充
FileDescriptorSet
。仅当您提供的字节是二进制 protobuf 内容时,这才有效 - 也就是说:一个已编译的模式。您可以通过使用带有 protoc 选项的 --descriptor_set_out 命令行工具来获取 compiled 模式。您现在实际传递的是构成文本模式的文本字节,这不是
parseFrom
所期望的。

如果没有编译的模式,您将需要一个运行时 .proto 解析器。我不知道是否有 Java 的; protobuf-net 包括一个 (protobuf-net.Reflection),但那是 C#/.NET。如果没有可用的运行时 .proto 解析器,您需要使用 shell 执行
protoc

根据其他答案,这是我正在开发的库中的一段可用的 Kotlin 代码片段。

https://github.com/asarkar/okgrpc


2
投票

这个想法是使用 os72/protoc-jar 写出编译后的模式/文件描述符。然后使用

FileDescriptorSet.parseFrom
 读取该文件,并递归其依赖项。

“脱壳”执行

protoc
的另一种选择是使用用 Java 编写的

.proto

1
投票

java中的原型解析器

”。 (我正在寻找一个解决
我的项目中的问题
)。 不要使用 java String 来保存 protobuf 有效负载。问题在于

String

-1
投票

Protobuf 适用于字节数组,并且数组中的确切表示必须保持不变。往返

String
不起作用。
    

© www.soinside.com 2019 - 2024. All rights reserved.