I am wondering if it's possible to have a enum with messages.
What I am trying to accomplish is to have nested messages, based on which enum is selected. The problem is easily solved by doing business logic checks using the optional identifier.
I am just looking for a more elegant business logic controll implementation than if-statement the hell out of the message to determine which code path to execute.
Something like this is what I have in mind. Is this possible to achieve?
message T {
enum A {
message T2 = 1;
}
}
No - enumerations are simply named 32-bit integers; but there is oneof - I wonder if that is what you are looking for:
message T {
oneof A {
T2 t2 = 1;
//...other options here
}
}
message T2 {}
Related
I want to be able to supply a pre-instantiated message by name rather than populating it from scratch. For example, given the following schema:
message Animal {
required int32 num_legs = 1;
required int32 num_eyes = 2;
}
message Zoo {
repeated Animal animals;
}
I want to be able quickly to define a Zoo in my config file by choosing from a set of known animals:
// config.json
zoo: {
animals: [snake, bird]
}
where snake and bird are already defined:
// animals.json
bird: {
num_legs: 2
num_eyes: 2
}
snake: {
num_legs: 0
num_eyes: 2
}
What's the most elegant way to do this?
The protobuf API has methods to convert protobuf⬌JSON. For C++ you can use util::JsonStringToMessage, other languages have their API versions too (you didn't specify a language). Wrap this in a simple helper function and use your language's multi-line string constant syntax to embed the message in JSON format directly into your source.
To get your named predefined messages, use a language that has string interpolation. (Not native to C++, unfortunately, but here is a SO answer talking about ways you might do it.)
I have a very simple music player, and I'd like to make it into a music server.
I plan in using gRPC to communicate between the clients and the server.
However, I'm not sure how I should design the protocol messages to handle the playback.
I envision two types of design :
A message for each type of query. This method defines clearly all possible actions, but seems to create a lot of redundant code.
message Play{
bool flag = 1; // False means Pause
}
message Stop{
bool flag = 1;
}
A unique message, with a key containing the action. This approach seems more flexible, but also more prone to errors. I could use an enum object to limits the possible actions though.
message Playback{
enum Action {
PLAY = 0;
STOP = 1;
}
Action action = 1;
}
Basically, I guess that what's I'm asking here is whether I should define an action by the type of the message or by its content.
Is there a rule of thumb or a design pattern to apply here ?
I would recommend to use the oneof construct here:
syntax = "proto3";
message Play {
}
message Stop {
}
message Command {
oneof command {
Play play = 1;
Stop stop = 2;
...
}
}
Empty messages are fine when there are no parameters that you need to pass, and this also leaves open an easy way to extend the messages in the future, for example changing Play to:
message Play {
string filename = 1;
}
would allow including an optional filename with the request, while retaining compatibility with the old version.
I've run into a use case where I'd like to move an enum declared inside a protocol buffer message to outside the message so that other messages van use the same Enum.
ie, I'm wondering if there are any issues moving from this
message Message {
enum Enum {
VALUE1 = 1;
VALUE2 = 2;
}
optional Enum enum_value = 1;
}
to this
enum Enum {
VALUE1 = 1;
VALUE2 = 2;
}
message Message {
optional Enum enum_value = 1;
}
Would this cause any issues de-serializing data created with the first protocol buffer definition into the second?
It doesn't change the serialization data at all - the location / name of the enums are irrelevant for the actual data, since it just stores the integer value.
What might change is how some languages consume the enum, i.e. how they qualify it. Is it X.Y.Foo, X.Foo, or just Foo. Note that since enums follow C++ naming/scoping rules, some things (such as conflicts) aren't an issue: but it may impact some languages as consumers.
So: if you're the only consumer of the .proto, you're absolutely fine here. If you have shared the .proto with other people, it may be problematic to change it unless they are happy to update their code to match any new qualification requirements.
How can we put a variant message ( one of a few message types ) inside a protobuf message?
message typeA {
....
}
message typeB {
....
}
message typeC {
[typeB|typeA] payload;
}
You need to do it like this:
message TypeC {
optional TypeA a = 1;
optional TypeB b = 2;
}
If there are a lot of variants, you might also want to add a tag field so that you don't have to check has_*() for each one.
This is covered in the Protobuf docs: https://developers.google.com/protocol-buffers/docs/techniques#union
PS. This missing feature of Protobufs is fixed in Cap'n Proto, a new serialization system by the same author (me): Cap'n Proto implements "unions" for this purpose. I had also implemented unions in Protobufs before leaving Google, but didn't manage to get my change merged into mainline before I left. Sorry. :(
EDIT: It looks like the Protobuf team eventually merged my change and released version 2.6.0 with it. :) See the oneof declaration.
Check out the new oneof feature in version 2.6: https://developers.google.com/protocol-buffers/docs/reference/java-generated#oneof
You can now do something like this:
message TypeC {
oneof oneof_name {
TypeA a = 1;
TypeB b = 2;
}
}
Fields in the same oneof will share memory and only one field can be set at the same time.
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?
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
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.
Alternatively to multiple optional fields, the oneof keyword can be used since v2.6 of Protocol Buffers.
message UnionMessage {
oneof data {
string a = 1;
bytes b = 2;
int32 c = 3;
}
}