2012-08-30 10 views
6

en resumen, ¿hay alguna manera de definir un mensaje protobuf que contenga otro mensaje de tipo arbitrario? Algo así como:Protobuf: anidando un mensaje de tipo arbitrario

message OuterMsg { 
    required int32 type = 1; 
    required Message nestedMsg = 2; //Any sort of message can go here 
} 

Sospecho que hay una manera de hacer esto debido a que en las diversas protobuf-implementaciones, los mensajes compilados se extienden desde una clase común Message base.

De lo contrario, supongo que tengo que crear un mensaje de base común para todo tipo de mensajes como este:

message BaseNestedMessage { 
    extensions 1 to max; 
} 

y luego hacer

message OuterMessage { 
    required int32 type = 1; 
    required BaseNestedMessage nestedMsg = 2; 
} 

Es esta la única manera de lograr esto?

Respuesta

6

No directamente, básicamente; El protocolo buffers desea conocer la estructura de antemano, y el tipo del mensaje no está incluido en el cable. La clase base común Message es un detalle de implementación para proporcionar un código de plomería común; la especificación de búferes de protocolo no incluye la herencia.

Hay, por lo tanto, limitadas opciones:

  • de uso diferentes de campo números por mensaje de tipo
  • serializar el mensaje por separado, e incluirlo como un tipo bytes, y transmitir el "¿qué es esto ? " información por separado (presumiblemente un discriminador/enumeración)

También debo señalar que algunas implementaciones pueden proporcionar más apoyo a esta; protobuf-net (C#/.NET) admite (por separado) tanto herencia como tipos de mensaje dinámicos (es decir, lo que tiene arriba), pero que está destinado principalmente para usar solo desde esa biblioteca a esa biblioteca. Como esto es todo además de la especificación (que permanece 100% válida en términos del formato de cable), puede ser innecesariamente complicado interpretar dichos datos de otras implementaciones.

+0

Como no puedo conocer todos los mensajes posibles con anticipación, iré por la solución de serialización por separado, utilizando un campo 'bytes', gracias – DeX3

8

La manera más popular de hacer es hacer que los campos opcionales para cada tipo de mensaje:

message UnionMessage 
{ 
    optional MsgType1 msg1 = 1; 
    optional MsgType2 msg2 = 2; 
    optional MsgType3 msg3 = 3; 
} 

Esta técnica también se describe en la documentación oficial de Google, y está bien soportado a través de implementaciones: https://developers.google.com/protocol-buffers/docs/techniques#union

1

Alternativamente a múltiples campos optional, se puede usar la palabra clave oneof desde v2.6 de Protocol Buffers.

message UnionMessage { 
    oneof data { 
    string a = 1; 
    bytes b = 2; 
    int32 c = 3; 
    } 
} 
Cuestiones relacionadas