Java中的genericsParsing

是否有可能在Java中以通用方式解析protobuf?

我查看了GeneratedMessage,找不到将任何PB字节缓冲区解析为GeneratedMessage的方法。

本质上,我试图将PB字节缓冲区解析为GeneratedMessage,然后我将使用reflection来检测其中的字段。

首先,您无法在不知道架构的情况下解析PB数据。 模式最初来自“.proto”文件,通常嵌入在protoc生成的代码中。 但是,您也可以告诉protoc以Java Protobuf库可用的格式存储模式:

 protoc --descriptor_set_out=mymessages.desc mymessages.proto 

然后将其加载到Java代码中:

 FileInputStream fin = new FileInputStream("mymessages.desc"); Descriptors.FileDescriptorSet set = Descriptors.FileDescriptorSet.parseFrom(fin); Descriptors.Descriptor md = set.getFile(0).getMessageType(0); 

获得消息的架构( Descriptor.Descriptor )后,解析消息很容易:

 byte[] data = ...; DynamicMessage m = DynamicMessage.parseFrom(md, data); 

DynamicMessage具有reflectionAPI,可让您查看字段。

凌乱的部分是调用protoc工具将“.proto”文件转换为可用的格式。 C ++ Protobuf库有一种直接加载“.proto”文件的方法,但遗憾的是Java Protobuf库没有。

我使用上一个protobuf v.3.1.0测试了工作解决方案

这是先前答案提出的升级解决方案。 感谢两位作者。

 import com.example.address.AddressBookManager; import com.example.address.AddressBookProtos.AddressBook; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.DynamicMessage; import java.io.File; import java.io.InputStream; public class DynamicMessageDemo { private static final String ADDRESS_BOOK_SOURCE_FILENAME = "test.ab"; private static final String ADDRESS_BOOK_DESC_FILENAME = File.separator + "address.desc"; public static void main(String[] args) throws Exception { InputStream is = DynamicMessageDemo.class .getResourceAsStream(ADDRESS_BOOK_DESC_FILENAME); FileDescriptorSet set = FileDescriptorSet.parseFrom(is); FileDescriptor fd = Descriptors.FileDescriptor.buildFrom( set.getFile(0), new Descriptors.FileDescriptor[]{} ); // "AddressBook" is the second message in my *.proto // so index must be '1' Descriptor messageType = fd.getMessageTypes().get(1); // for testing purpose AddressBook book = AddressBookManager.readFromFile(ADDRESS_BOOK_SOURCE_FILENAME); byte[] data = book.toByteArray(); DynamicMessage message = DynamicMessage.parseFrom(messageType, data); System.out.println("\n Dynamic message:\n" + message); } } 

这是正确的例子:

 private static DynamicMessage parseData(byte[] data) throws IOException, DescriptorValidationException { FileInputStream fin = new FileInputStream("test.desc"); DescriptorProtos.FileDescriptorSet set = DescriptorProtos.FileDescriptorSet.parseFrom(fin); Descriptor md = Descriptors.FileDescriptor.buildFrom(set.getFile(0), new Descriptors.FileDescriptor[] {}).findMessageTypeByName("Person"); return DynamicMessage.parseFrom(md, data); } 

您可以使用UnknownFieldSet来解析通用的protobuf消息。

然后,您可以使用提供的方法获取单个字段(例如asMap() , hasField() , getField() )

例如(从这个问题中获取的数据):

  byte[] msg = new byte[] { 0x0a, 0x10, 0x08, 0x7f, (byte)0x8a, 0x01, 0x04, 0x08, 0x02, 0x10, 0x03, (byte)0x92, 0x01, 0x04, 0x08, 0x02, 0x10, 0x03, 0x18, 0x01}; UnknownFieldSet eee = UnknownFieldSet.parseFrom(msg); System.out.println(eee.toString()); 

赠送:

 1: { 1: 127 17: { 1: 2 2: 3 } 18: { 1: 2 2: 3 } } 3: 1