Java中的泛型Parsing

Jim*_*imm 9 java protocol-buffers

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

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

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

Kan*_*dan 14

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

protoc --descriptor_set_out=mymessages.desc mymessages.proto
Run Code Online (Sandbox Code Playgroud)

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

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

获得消息的模式后(Descriptor.Descriptor)解析消息很容易:

byte[] data = ...;
DynamicMessage m = DynamicMessage.parseFrom(md, data);
Run Code Online (Sandbox Code Playgroud)

DynamicMessage 有一个反射API,可以让你浏览字段.

凌乱的部分是呼吁protoc工具将".proto"文件转换为可用的格式.C++ Protobuf库有一种直接加载".proto"文件的方法,但不幸的是Java Protobuf库没有.


vlp*_*vlp 6

您可以使用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());
Run Code Online (Sandbox Code Playgroud)

给予:

1: {
  1: 127
  17: {
    1: 2
    2: 3
  }
  18: {
    1: 2
    2: 3
  }
}
3: 1
Run Code Online (Sandbox Code Playgroud)


Беш*_*вин 5

这是正确的例子:

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);
}
Run Code Online (Sandbox Code Playgroud)


Rib*_*b47 5

我已经用最后一个 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);
    }
}
Run Code Online (Sandbox Code Playgroud)