Общий разбор PB в Java - PullRequest
       21

Общий разбор PB в Java

9 голосов
/ 27 октября 2010

Возможно ли синтаксический анализ protobuf в Java?

Я посмотрел в GeneratedMessage и не смог найти способ для анализа любого байтового буфера PB в GeneratedMessage.

По сути, я пытаюсь проанализировать буфер байтов PB в GeneratedMessage, а затем использовать отражение для обнаружения полей внутри него.

Ответы [ 4 ]

13 голосов
/ 14 марта 2011

Прежде всего, вы не можете анализировать данные 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 имеет отражающий API, который позволяет просматривать поля.

Беспорядочная часть обращается к инструменту protoc для преобразования файла .proto в пригодный для использования формат. Библиотека C ++ Protobuf позволяет напрямую загружать файлы ".proto", но, к сожалению, библиотека Java Protobuf этого не делает.

3 голосов
/ 02 ноября 2016

У меня есть работающее решение, протестированное с последним 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);
    }
}
2 голосов

Это правильный пример:

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);
}
0 голосов
/ 15 сентября 2018

Вы можете использовать UnknownFieldSet для анализа общих сообщений protobuf. * ​​1003 *

Затем вы можете получить отдельные поля, используя предоставленные методы (например, 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...