Определить класс ProtoBuf из байтового массива - PullRequest
1 голос
/ 06 февраля 2020

Я пишу программу, которая работает с двумя прото-сообщениями, мне нужно обработать байт [], отправленный из разных источников, который отправляет либо сообщение foo, либо сообщение bar. Поскольку я не могу выяснить, к какому сообщению оно принадлежит, я использовал Any Class (поставляется вместе с protobuf), чтобы проанализировать массив байтов и найти, к какому классу он принадлежит, но столкнулся с ошибкой времени компиляции. Есть ли какой-нибудь другой метод, который я могу использовать, чтобы определить, добавлю ли я в будущем больше классов прототипов сообщений?

//Foo.proto

syntax = "proto3";

option java_outer_classname = "FooProto";

message Foo {
    int32 a = 1;
}

и второй прото

//Bar.proto
syntax = "proto3";

option java_outer_classname = "BarProto";

message Bar {
    int32 b = 1;
}

Код:

Any anyEvent = Any.parseFrom(protoBytes);
if (any.is(Foo.class)
{
  Foo foo = any.unpack(Foo.class);
  ...
} else {
  Bar bar = any.unpack(Bar.class);
  ...
}

Ошибка в операторе if при попытке вызвать any.is ():

Метод (Class ) в типе Any не применим для аргументов (Class )

1 Ответ

1 голос
/ 06 февраля 2020

Any не означает «любой»; это означает «тип, сериализованный через Any». Если вы не сохранили это с Any: вы не можете декодировать это через Any.

Ключевым моментом здесь является то, что protobuf не включить метаданные типа в полезную нагрузку сообщения. Если у вас есть BLOB, вы обычно не можете знать , какой тип сообщения. Any решает это путем кодирования типа сообщения в сообщении-обертке , но у вас его здесь не будет.


Если ваш дизайн должен иметь API, который принимает два различные не Any типы сообщений без предварительного знания о них: у вас, вероятно, плохой дизайн. Потому что не работает с protobuf. На проводе буквально нет разницы между Foo с a=42 и Bar с b=42; полезные данные идентичны :

Foo с a=42 байтами 08 2A; Bar с b=42 - байты 08 2A. 08 означает «поле 1, закодированное как varint», 2A - это varint с необработанным значением 42.

Лучшим дизайном может быть сообщение обертки , специфицирующее c для вашего Сценарий :

message RootMessage {
  oneof test_oneof {
     Foo foo = 1;
     Bar bar = 2;
  }
}

Это добавляет слой оболочки , аналогичный тому, как работает Any, но гораздо эффективнее - он просто знает, как отличить guish между вашими известными типами как целым числом, вместо того, чтобы обрабатывать все возможные типы (как имя корневого типа).

...