Im essayant de passer à l'utilisation de protobuf version 3 et de rester rétrocompatible avec la version 2. Semble fonctionner sauf pour une chose - dans proto-2, vous pouvez définir vos propres valeurs par défaut, mais dans proto 3, vous ne pouvez pas. Si vous avez choisi une valeur par défaut dans proto-2 qui n'est pas la valeur par défaut standard dans proto-3, vous avez un problème. Par exemple, dans proto-2:
message Record {
required uint32 fileno = 1;
required uint64 pos = 2;
optional uint64 bmsPos = 3 [default = 0];
optional uint32 scanMode = 4 [default = 9999];
}
maintenant dans proto-3 doit être:
message Record {
uint32 fileno = 1;
uint64 pos = 2;
uint64 bmsPos = 3;
uint32 scanMode = 4;
}
Dans proto-2 et proto-3, les valeurs manquantes ne sont pas envoyées dans le message. Mais l'API proto-3 ne vous dit pas si la valeur par défaut est dans le message ou non, elle vous indique simplement la valeur.
Ainsi, le récepteur proto-3 reçoit un message et me dit que scanMode = 0. Si ce message provient d'un expéditeur proto-2, alors 1) l'expéditeur proto-2 a placé un 0 dans le message, ou 2) le proto- 2 expéditeur a défini la valeur sur 9999 (la valeur par défaut), et donc la valeur n'est pas envoyée, et le récepteur proto-3 l'interprète comme un 0. Sans savoir si la valeur est présente dans le message ou non, mon code ne peut pas ambiguïter , même s'il sait si le message provient d'un expéditeur proto-2 ou proto-3.
Notez qu'il n'y a aucun problème avec le champ bmsPos dans l'exemple, car le message proto-2 utilise la même valeur par défaut que proto-3 (0). Mais s'il vous arrivait d'avoir choisi une valeur par défaut différente de proto-3, alors je ne vois pas comment passer à proto-3 et être rétrocompatible.
Il s'avère qu'il existe un moyen de savoir si une valeur par défaut est réellement manquante ou non (merci à certains amis de Google pour cette réponse):
message Record {
uint32 fileno = 1;
uint64 pos = 2;
uint64 bmsPos = 3;
oneof scanMode_present {
uint32 scanMode = 4;
}
uint32 version = 5; // set to >= 3 for protobuf 3
}
Le code de génération a des méthodes supplémentaires pour détecter si les champs oneof sont définis, en utilisant la méthode getXXXcase ():
int scanMode = proto.getScanMode();
boolean isMissing = proto.getScanModePresentCase() == Record.ScanModePresentCase.SCANMODEPRESENT_NOT_SET;
if (isMissing) {
boolean isProto3 = proto.getVersion() >= 3;
scanMode = (isProto3) ? 0 : 9999;
}
Avec cette `` astuce '', j'ai mis à niveau vers proto-3 avec une compatibilité descendante avec des valeurs par défaut proto-2 non standard.