I'm doing communications between a .Net-based program on a Windows system and Android devices. On the .Net end I'm using Marc Gravell's great protobuf-net program, and on the Android end I'm using David Yu's great protostuff program.
My procedure (so far) is to use the .Net classes as the defining classes. I use the protobuf-net Serializer.GetProto() method to generate a .proto file, and protostuff's protostuff-compiler program to generate Java classes that correspond to the .Net classes, more-or-less.
This seems to work fairly well, except that I've run into a problem with inheritance. Yes, I know, inheritance isn't supposed to work with protocol buffers. But both protobuf-net and protostuff have implemented support for inherited classes, each in its own way.
So my question is, does anyone have any suggestion of a simple way to get inherited C# classes to map to inherited Java classes, and vice-versa?
Here's an example of what I'm working with. These are the C# classes:
public /* abstract */ class ProgramInfoBase
{
private string _programName;
private string _programVersion;
[ProtoMember(1)]
public string ProgramName
{
get { return _programName; }
set { _programName = value; }
}
[ProtoMember(2)]
public string ProgramVersion
{
get { return _programVersion; }
set { _programVersion = value; }
}
}
public class ProgramInfoAndroid : ProgramInfoBase
{
private string _androidDeviceName;
[ProtoMember(1)]
public string AndroidDeviceName
{
get { return _androidDeviceName; }
set { _androidDeviceName = value; }
}
}
public class ProgramInfoWindows : ProgramInfoBase
{
private string _windowsMachineName;
[ProtoMember(1)]
public string WindowsMachineName
{
get { return _windowsMachineName; }
set { _windowsMachineName = value; }
}
}
And here's one of my .proto files:
package Merlinia.MessagingDefinitions;
option java_package = "com.Merlinia.MMessaging_Test.protostuff";
message ProgramInfoAndroid {
optional string AndroidDeviceName = 1;
}
message ProgramInfoBase {
optional string ProgramName = 1;
optional string ProgramVersion = 2;
// the following represent sub-types; at most 1 should have a value
optional ProgramInfoAndroid ProgramInfoAndroid = 1001;
optional ProgramInfoWindows ProgramInfoWindows = 1002;
}
message ProgramInfoWindows {
optional string WindowsMachineName = 1;
}
Running that through protostuff's protostuff-compiler program produces three separate Java classes, which is to be expected. But what I'd like is to have it generate the corresponding C# class inheritance for the Java classes, and for the serialization and deserialization between protobuf-net and protostuff to support the inherited classes at both ends.
EDIT:
I've now changed my mind. Please see the following question: How to get protobuf-net to flatten and unflatten inherited classes in .Net?
Firstly, note that polymorphism is not defined in the protobuf specification; any implementations are bespoke. It would be nice if they were the same, though.
Basically, it looks like they adopt fundamentally different paradigms; protobuf-net treats sub-types as nested objects starting from the base-type downwards, as per the .proto that you have posted (which I assume came from
GetProto
, due to the familiar comment). This choice was made for many reasons, including:protostuff, however, does things a different way; glancing at the repo, it writes the type name into field 127 (and restricts the data fields to 126), and uses that name to perform type resolution. I would guess (untested) this means that in .proto terms the schema is therefore:
So, at this point you have a few choices:
For example, if you keep the java code as polymorphic, the .NET code would need something like the above with the magic type name, but: this would get really messy of there were conflicts - for example, if field 1 was
int Foo
in one sub-type, andstring Bar
in another sub-type: bad things; you'd also need to hard-code/recognize the pojo type names. Without trying to blow my own trumpet, these are exactly the type of issues, conflicts and name dependencies that I worked hard to circumvent in the protobuf-net implementationIf you keep the protobuf-net as polymorphic, then you could presumably just start from the .proto you posted, and just check (after deserialization on the java side) whether ProgramInfoAndroid or ProgramInfoWindows is non-null; then based on which is non-null, map it to one of 3 different domain types.