Парсер Protobuf разбирает другие объекты?

Я использую буферы протоколов для своего проекта на Java. Я обнаружил, что синтаксический анализатор объекта protobuf анализирует другие данные Protobuf и не выдает исключение. Вместо этого он возвращает объект типа парсера без каких-либо данных (не экземпляр по умолчанию)

Ниже мой тестовый прото файл

option java_package = "tester";
option java_outer_classname = "TestProto";

message A{
    string message = 1;
}

message B{
    int64 id = 1;
}

ниже мой тестовый код

 TestProto.A a = TestProto.A.newBuilder().setMessage("My Test Message").build();
 TestProto.B b = TestProto.B.getDefaultInstance().getParserForType().parseFrom(a.toByteString());

 System.out.println("Is default instnace :" + (b.getDefaultInstanceForType() == b));

этот код работает без исключений, и результат «ложь».

Я не могу понять это поведение, мне нужна ситуация, когда мне нужно проанализировать некоторые сериализованные объекты protobuf, и если один парсер не работает, я должен попробовать другой парсер. Как я могу это решить.

Благодарю.


person Bhanuka Yd    schedule 01.04.2018    source источник
comment
Проверьте содержимое getUnknownFields (или getUnknownFieldSet, или подобного. Я забыл точное имя метода).   -  person Andy Turner    schedule 02.04.2018
comment
Но также, в целом, b.getDefaultInstanceForType() == b неверно: используйте equals для сравнения экземпляров.   -  person Andy Turner    schedule 02.04.2018
comment
Как правило, вам будет трудно с этим, потому что поля optional по умолчанию в proto3. Это означает, что если два сообщения имеют совершенно разные поля (и идентификаторы полей), они по-прежнему могут быть назначены друг другу. Только содержимое будет потеряно, так как синтаксический анализатор предполагает, что это просто необязательное поле, о котором он не знает.   -  person Matthias247    schedule 02.04.2018
comment
Однако в этом конкретном примере должна быть ошибка, поскольку один и тот же идентификатор поля (1) используется для 2 разных типов.   -  person Matthias247    schedule 02.04.2018
comment
@Matthias247 Matthias247 это может быть синтаксический анализ с помощью упакованной логики, которая будет соответствовать префиксу длины; Потребуется довольно много времени, чтобы не вызвать нарушение варинта, но теоретически это возможно; Я бы подумал, что это не произойдет, если это не повторится, но ... мда   -  person Marc Gravell    schedule 02.04.2018
comment
@Энди, это не неизвестное поле.   -  person Marc Gravell    schedule 02.04.2018
comment
@Matthias247 продолжает мысль, которая подтверждает, что в качестве причины указана упаковка: чистый ASCII всегда будет допустимым вариантом. Я ожидаю, что объект имеет id = 101   -  person Marc Gravell    schedule 02.04.2018
comment
@AndyTurner Я проверял, возвращает ли парсер тот же одноэлементный объект (экземпляр по умолчанию), проверяя ссылку, поэтому я использовал ==   -  person Bhanuka Yd    schedule 02.04.2018
comment
@AndyTurner Я также использовал equals, и в этом случае он тоже возвращает false   -  person Bhanuka Yd    schedule 02.04.2018
comment
@AndyTurner, использующий getUnknownFields, может решить проблему здесь, но проверка IMO на наличие какого-либо неизвестного поля и игнорирование сообщения, если оно есть, приведет к невозможности обновить структуру сообщения в будущем. Поэтому я приму ответ Марка Гравелла и рассмотрю более подробное изменение дизайна приложения.   -  person Bhanuka Yd    schedule 02.04.2018
comment
Спасибо за быстрые ответы :D   -  person Bhanuka Yd    schedule 02.04.2018


Ответы (1)


Protobuf предполагает, что обе стороны заранее знают и согласовывают структуру данных. Если вы попытаетесь интерпретировать сообщение с радикально отличной структурой, то никаких гарантий не будет.

  • это может выдать ошибку
  • это может сработать и преподнести вам благонамеренную тарабарщину
  • он мог работать и сохранять все необходимое как неизвестные поля

Все возможно.

В основном: вы не можете полагаться на это поведение.

Примечание: существуют гарантии в отношении определенных изменений, таких как добавление или удаление полей (гарантируя, что они не будут повторно использоваться позже с другими типами/значениями). Это нормально и ожидаемо. Но другие изменения просто не определяются.


Мне нужна ситуация, когда мне нужно проанализировать некоторые сериализованные объекты protobuf, и если один парсер не работает, я должен попробовать другой парсер. Как я могу это решить.

Вы не можете.

person Marc Gravell    schedule 01.04.2018
comment
Примечание для себя: я на 99,5% уверен, что protobuf-net действительно выдаст исключение в этом случае. Поскольку это неопределенный сценарий, ни одно поведение не является более правильным или более неправильным, но теперь мне интересно, должен ли я хотя бы заставить его вести себя одинаково. Но на самом деле: если вы столкнулись с этой проблемой, вы уже довольно сильно испортили свои данные, так что... может быть, лучше просто оставить это в покое. На это, конечно, не стоит тратить много времени. Может быть случай, когда я изменил свое упакованное повторяющееся поле (в котором когда-либо было одно значение) на необязательное поле, и теперь оно терпит неудачу, хотя - person Marc Gravell; 02.04.2018
comment
Вы не можете. Может не всегда верно. В случаях, когда вы можете изменить схему входящих данных, вы можете спроектировать ее с помощью oneof ключевое слово или тип Any и какое-то описание какого типа на самом деле содержит поле Any. - person plastique; 05.11.2019
comment
Изменение @plastique на Any является изменением макета; oneof не применяется в случае, указанном в вопросе; так что да, может быть способ справиться с этим в определенных случаях, но: не показанный - person Marc Gravell; 05.11.2019