protobuf google protocol-buffers

protocol buffers - google - Actualización de protobuf de la versión 2 a 3: incompatible con los valores predeterminados de protobuf



google:: protobuf (1)

Estoy intentando actualizar a usar protobuf versión 3, y seguir siendo compatible con la versión 2. Parece que funciona excepto por una cosa: en proto-2 puedes establecer tus propios valores predeterminados, pero en proto 3, no puedes. Si eligió un valor predeterminado en proto-2 que no es el valor predeterminado estándar en proto-3, entonces tiene un problema. Por ejemplo, en proto-2:

message Record { required uint32 fileno = 1; required uint64 pos = 2; optional uint64 bmsPos = 3 [default = 0]; optional uint32 scanMode = 4 [default = 9999]; }

ahora en proto-3 debe ser:

message Record { uint32 fileno = 1; uint64 pos = 2; uint64 bmsPos = 3; uint32 scanMode = 4; }

Tanto en proto-2 como en proto-3, los valores faltantes no se envían en el mensaje. Pero la API proto-3 no le dice si el valor predeterminado está en el mensaje o no, simplemente le dice el valor.

Entonces el receptor proto-3 recibe un mensaje y me dice que scanMode = 0. Si ese mensaje vino de un remitente proto-2, entonces 1) el remitente proto-2 colocó un 0 en el mensaje, o 2) el proto- 2 el remitente establece el valor en 9999 (el valor predeterminado), por lo que el valor no se envía y el receptor proto-3 lo interpreta como un 0. Sin saber si el valor está presente en el mensaje o no, mi código no puede ser ambiguo. , incluso si sabe si el mensaje proviene de un remitente proto-2 o proto-3.

Tenga en cuenta que no hay ningún problema con el campo bmsPos en el ejemplo, ya que el mensaje proto-2 usa el mismo valor predeterminado que proto-3 (0). Pero si ha elegido un valor predeterminado que no es el mismo que proto-3, entonces no veo cómo actualizar a proto-3 y ser compatible con versiones anteriores.


Resulta que hay una manera de averiguar si falta un valor predeterminado o no (gracias a algunos amigos de google por esta respuesta):

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 }

El código generado tiene métodos adicionales para detectar si uno de los campos está configurado, usando el método 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; }

  • Tenga en cuenta que el nombre de oneof es arbitrario, he adoptado la convención fieldname_present .
  • El oneof no agrega nada al formato de cable, por lo que sigue siendo compatible con los mensajes proto-2.
  • Puede agregar la información de la versión en cualquier lugar que tenga sentido, la puse en el mensaje de registro para este ejemplo.

Con este ''truco'', actualicé a proto-3 con compatibilidad hacia atrás con valores proto-2 no estándar.