web-dev-qa-db-fra.com

Vérifiez si un champ a été défini dans le tampon de protocole 3

Je migre une application Java des tampons de protocole 2 vers le tampon de protocole 3.

Dans proto 2 pour vérifier si un champ est défini, vous disposez de la méthode hasfield() pour laquelle un exemple Java code généré est:

public boolean hasText() {
  return ((bitField0_ & 0x00000004) == 0x00000004);
}

Cependant, dans la proto 3, il a été supprimé. Comment vérifiez-vous si un champ a été défini dans proto 3?

8
user1798617

Une des approches suggérées est donnée ici :

# NOTE: As of proto3, HasField() only works for message fields, not for
#       singular (non-message) fields. First try to use HasField and
#       if it fails (with a ValueError) we manually consult the fields.
try:
    return message_pb.HasField(property_name)
except ValueError:
    all_fields = set([field.name for field in message_pb._fields])
    return property_name in all_fields

Aussi, depuis la même page:

Dans proto3, la présence de champs pour les champs scalaires n'existe tout simplement pas. Votre modèle mental pour proto3 devrait être qu'il s'agit d'une structure C++ ou Go. Pour les entiers et les chaînes, il n'y a rien de tel que d'être défini ou non, il a toujours une valeur. Pour les sous-messages, il s'agit d'un pointeur vers l'instance de sous-message qui peut être NULL, c'est pourquoi vous pouvez tester sa présence.

4
P.W

Je pense que l'approche recommandée, qui n'est pas idéale en raison des décisions de conception prises dans proto3, consiste à vérifier les valeurs standard. Vous ne pouvez pas vérifier explicitement si un champ est défini ou non. Comme accès à msg._fields n'est pas recommandé comme décrit ici la seule chose qui reste est de vérifier si le champ est défini sur sa valeur standard:

if msg.textfield.isEmpty() {
    //assume textfield is not set
}
1
Gigi

La meilleure suggestion que j'ai vue pour cela dans proto3 est d'envelopper votre champ dans un singleton. Cela vous permettra de vérifier à nouveau la présence/absence, similaire à proto2.

message blah
{
    oneof foo_ { sint32 foo = 1; }
}

Dans Python est extrêmement fluide car foo peut être directement opéré comme un scalaire comme s'il n'était pas à l'intérieur d'un oneof).

Malheureusement, pour Java je pense que la prise en charge de l'un est beaucoup plus laide. Google a également volontairement supprimé la fonction de classe générée par hasFoo () dans proto3. Vous devriez donc consulter la getFooCase () de l'un à la place pour vérifier la présence ou l'absence.

https://developers.google.com/protocol-buffers/docs/reference/Java-generated#oneof-fields

Oui, je me rends compte que cela signifie des tonnes de l'un et de tous les tracas qu'ils apportent. Du côté positif, il n'y a pas de frais généraux sur le fil.

La deuxième meilleure suggestion que j'ai vue est d'utiliser un sous-message pour envelopper votre scalaire car la présence/l'absence de sous-messages est toujours prise en charge. Il existe les types bien connus (WKT) dans google.protobuf.wrappers.proto. Si vous les utilisez, vous pouvez même obtenir un traitement spécial supplémentaire dans votre langue préférée où le scalaire encapsulé peut être facilement opéré comme si le sous-message contenant n'existait pas (ou du moins j'ai lu, pas entièrement sûr sur ce point moi-même ).

0
jschultz410