Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protobuf: Nesting a message of arbitrary type

in short, is there a way to define a protobuf Message that contains another Message of arbitrary type? Something like:

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

I suspect that there's a way to do this because in the various protobuf-implementations, compiled messages extend from a common Message base class.

Otherwise I guess I have to create a common base Message for all sorts of messages like this:

message BaseNestedMessage {
    extensions 1 to max;
}

and then do

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

Is this the only way to achieve this?

like image 412
DeX3 Avatar asked Aug 30 '12 08:08

DeX3


People also ask

Why did Proto3 remove optional?

We have seen production issues caused by this multiple times and it's pretty much banned everywhere inside Google for anyone to add/remove required fields. For this reason we completely removed required fields in proto3. After the removal of "required", "optional" is just redundant so we removed "optional" as well.

What is the difference between proto2 and Proto3?

Proto3 is the latest version of Protocol Buffers and includes the following changes from proto2: Field presence, also known as hasField , is removed by default for primitive fields. An unset primitive field has a language-defined default value.

Is proto2 deprecated?

Actually we have no plans to deprecate proto2 and we are still actively developing it, so you can really choose either one without having to worry about support going away.

Is protobuf more efficient than JSON?

JSON is usually easier to debug (the serialized format is human-readable) and easier to work with (no need to define message types, compile them, install additional libraries, etc.). Protobuf, on the other hand, usually compresses data better and has built-in protocol documentation via the schema.


2 Answers

The most popular way to do is to make optional fields for each message type:

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

This technique is also described in the official Google documentation, and is well-supported across implementations: https://developers.google.com/protocol-buffers/docs/techniques#union

like image 52
jpa Avatar answered Sep 19 '22 16:09

jpa


Not directly, basically; protocol buffers very much wants to know the structure in advance, and the type of the message is not included on the wire. The common Message base-class is an implementation detail for providing common plumbing code - the protocol buffers specification does not include inheritance.

There are, therefore, limited options:

  • use different field-numbers per message-type
  • serialize the message separately, and include it as a bytes type, and convey the "what is this?" information separately (presumably a discriminator / enumeration)

I should also note that some implementations may provide more support for this; protobuf-net (C# / .NET) supports (separately) both inheritance and dynamic message-types (i.e. what you have above), but that is primarily intended for use only from that one library to that one library. Because this is all in addition to the specification (remaining 100% valid in terms of the wire format), it may be unnecessarily messy to interpret such data from other implementations.

like image 39
Marc Gravell Avatar answered Sep 18 '22 16:09

Marc Gravell