InvalidProtocolBufferException в клиенте Java при десериализации данных protobuf с сервера C++
У меня есть сообщение protobuf как это:
message Update {
Path path = 1; // The path (key) for the update.
Value value = 2 [deprecated=true]; // The value (value) for the update.
TypedValue val = 3; // The explicitly typed update value.
}
// TypedValue is used to encode a value being sent between the client and
// target (originated by either entity).
message TypedValue {
oneof value {
string string_val = 1; // String value.
int64 int_val = 2; // Integer
....
google.protobuf.Any any_val = 9; // protobuf.Any encoded bytes.
....
}
}
На стороне сервера (C++) мы устанавливаем это поле следующим образом (LLDP является внешним классом, а Interfaces находится внутри него):
openconfig_lldp::Lldp out;
GetLldpProto(&out);
update->mutable_val()->mutable_any_val()->PackFrom(out.interfaces());
На стороне клиента (Java) мы извлекаем это поле следующим образом:
OpenconfigLldp.Lldp.Interfaces interfaces = update.getVal().getAnyVal().unpack(OpenconfigLldp.Lldp.Interfaces.class);
Это вызывает исключение InvalidProtocolBufferException. Когда я сбрасываю "обновление" в моем клиенте Java, я вижу это:
path {
elem {
name: "lldp"
}
elem {
name: "interfaces"
}
}
val {
any_val {
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
value: "\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/1\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/2\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/3\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/4\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n"
}
}
Type_url мне кажется правильным. Что я здесь не так делаю?
Спасибо за ваше время.
РЕДАКТИРОВАНИЕ № 1:
Я посмотрел на строку исключения. Это "Тип сообщения Any не соответствует данному классу".
Тот же файл протока используется для C++ и Java, но я вижу "openconfig_lldp.Lldp.Interfaces" в C++, где как "OpenconfigLldp.Lldp.Interfaces" в Java. Нужно выяснить почему..
РЕДАКТИРОВАТЬ № 2:
Используется тот же файл.proto. В данном случае это:
openconfig_lldp.proto
---------------------
syntax = "proto3";
package openconfig.openconfig_lldp;
message Lldp {
message Config {
....
....
}
....
....
}
В случае с Java я вижу родительский класс как OpenconfigLldp в пакете с именем openconfig_lldp.
package openconfig.openconfig_lldp;
public final class OpenconfigLldp {
private OpenconfigLldp() {}
....
....
/**
* Protobuf type {@code openconfig.openconfig_lldp.Lldp}
*/
public static final class Lldp extends com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:openconfig.openconfig_lldp.Lldp)
....
....
}
В C++ я не вижу ни одного сгенерированного класса под названием OpenconfigLldp. Вместо этого это просто "Lldp"
Таким образом, type_url в Any.protobuf не соответствует. C++ сторона ставит это как
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
В то время как на стороне Java я использую:
OpenconfigLldp.Lldp.Interfaces interfaces = update.getVal().getAnyVal().unpack(OpenconfigLldp.Lldp.Interfaces.class);
У кого-нибудь есть мысли о том, почему в выводе Java Protoc есть класс-обертка?
РЕДАКТИРОВАТЬ № 3
Видимо, похоже, что это из-за "external_class_name". В коде Java у меня есть внешний класс "OpenconfigLldp".
Формат type_url:
type.googleapis.com/packagename.messagename
Итак, код C++ устанавливает это в openconfig_lldp.Lldp.Interfaces. Но это сопоставляется с OpenconfigLldp.Lldp.Interfaces в Java.
Как я мог обойти это?
ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ и ЗАКЛЮЧИТЕЛЬНЫЙ ВОПРОС
После нескольких копаний это то, что я узнал. По умолчанию type_url:
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
Что касается Java, я посмотрел на реализацию Any. Он пытается сравнить это с:
openconfig.openconfig_lldp.Lldp.Interfaces
Я узнал об этом, напечатав:
Lldp.Interfaces defaultInstance = (Lldp.Interfaces)Internal.getDefaultInstance(Lldp.Interfaces.class);
logger.info("full descriptor name: " + defaultInstance.getDescriptorForType().getFullName());
Итак, я взломал сторону C++, чтобы отправить:
update->mutable_val()->mutable_any_val()->set_type_url(std::string("type.googleapis.com/openconfig.openconfig_lldp.Lldp.Interfaces"));
Так что, думаю, я знаю, что здесь происходит!
Спасибо за чтение всех правок.
1 ответ
Я не уверен, правильно ли я понимаю, что происходит - в идеале, квалифицированные имена должны быть в пространствах имен буфера протокола - не должны иметь значения языковые соответствия.
Если вопрос все еще открыт, я бы порекомендовал переместить его ядро наверх, сохранив правки как "то, что я сделал до сих пор".
Возможно, это какая-то ошибка, которую можно обойти с помощью следующих опций:
java_multiple_files
java_outer_classname
Подробнее об этих параметрах можно узнать здесь: https://developers.google.com/protocol-buffers/docs/proto3