我尝试用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);
}
但是,在执行上一个方法时,会引发一个异常,并显示消息“Protocol message tag had invalid wire type”。我使用了Google的example .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)
有什么想法吗?谢谢!
4条答案
按热度按时间46qrfjad1#
看起来像是在尝试使用
FileDescriptorSet.parseFrom
填充FileDescriptorSet
。只有当你提供的字节 * 是 * 二进制protobuf内容时,这才有效-也就是说:一个 * 编译的 * 模式。您可以通过使用protoc
命令行工具和--descriptor_set_out
选项来获得一个 compiled 模式。您现在实际传递的是组成文本模式的文本字节,这不是parseFrom
所期望的。如果没有编译的模式,您将需要runtime .proto解析器。我不知道有一个用于Java的; protobuf-net包含一个(protobuf-net.Reflection),但那是C#/. NET。如果没有可用的runtime .proto解析器,则需要改为shell执行
protoc
。cvxl0en22#
根据其他答案,这里有一个来自我正在开发的库的工作Kotlin代码片段。https://github.com/asarkar/okgrpc
其思想是使用os72/protoc-jar写出编译后的模式/文件描述符。然后使用
FileDescriptorSet.parseFrom
读取该文件,并递归其依赖项。8yparm6h3#
另一种方法是使用Java编写的
.proto
解析器来执行execprotoc
。似乎有一些浮动-谷歌像“* proto parser in java *”的东西。(我正在寻找一个an issue in my project)。rks48beu4#
不要使用java
String
来保存protobuf负载。问题是String
在幕后进行翻译,并对字符集进行假设。Protobuf适用于字节数组,数组中的确切表示必须保持不变。往返
String
不起作用。