Je dois spécifier un message avec un champ optionnel dans protobuf (syntaxe proto3). En ce qui concerne la syntaxe proto 2, le message que je veux exprimer ressemble à ceci:
message Foo {
required int32 bar = 1;
optional int32 baz = 2;
}
A ma connaissance, le concept "optionnel" a été supprimé de la syntaxe proto 3 (avec le concept requis). Bien que l'alternative ne soit pas claire - utiliser la valeur par défaut pour indiquer qu'un champ n'a pas été spécifié par l'expéditeur, laisse une ambiguïté si la valeur par défaut appartient au domaine des valeurs valides (considérons par exemple un type booléen).
Alors, comment suis-je censé encoder le message ci-dessus? Je vous remercie.
Dans proto3, tous les champs sont "facultatifs" (en ce sens que l'expéditeur ne parvient pas à les définir). Mais les champs ne sont plus "nuls", en ce sens qu'il n'y a aucun moyen de faire la différence entre un champ explicitement défini sur sa valeur par défaut et le fait de ne pas l'avoir été du tout.
Si vous avez besoin d'un état "null" (et qu'il n'y a pas de valeur hors plage que vous pouvez utiliser pour cela), vous devrez plutôt l'encoder comme un champ séparé. Par exemple, vous pourriez faire:
message Foo {
bool has_baz = 1;
int32 baz = 2;
}
Vous pouvez aussi utiliser oneof
:
message Foo {
oneof baz {
bool baz_null = 1; // always set this to "true" when using
int32 baz_value = 2;
}
}
La version oneof
est plus explicite et plus efficace sur le réseau, mais elle nécessite de comprendre comment les valeurs oneof
fonctionnent.
Enfin, une autre option parfaitement raisonnable est de rester avec proto2. Proto2 n'est pas obsolète et de nombreux projets (y compris Google) dépendent en grande partie des fonctionnalités de proto2 qui sont supprimées dans proto3 et ne basculeront donc probablement jamais. Donc, il est prudent de continuer à l'utiliser dans un avenir proche.
D'après la réponse de Kenton, une solution simple mais efficace ressemble à ceci:
message Foo {
oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2
int32 baz = 1;
}
}
Pour développer la suggestion de @cybersnoopy ici
si vous aviez un fichier .proto avec un message comme celui-ci:
message Request {
oneof option {
int64 option_value = 1;
}
}
Vous pouvez utiliser les options de cas fournies (code généré par Java) :
Donc, nous pouvons maintenant écrire du code comme suit:
Request.OptionCase optionCase = request.getOptionCase();
OptionCase optionNotSet = OPTION_NOT_SET;
if (optionNotSet.equals(optionCase)){
// value not set
} else {
// value set
}
vous pouvez trouver si l'un a été initialisé en comparant les références avec l'instance par défaut:
GRPCContainer container = myGrpcResponseBean.getContainer();
if (container.getDefaultInstanceForType() != container) {
...
}