Search code examples
pythonjsonprotocol-buffersenumeration

protobuf MessageToJson removes fields with value 0


I'm writing a Python script that receives protobufs, converts them to json objects, and pushes them to another service. I use json.loads(MessageToJson(protobuf)) to convert the protobuf to a python dictionary object. Later I convert it back to json with json.dumps(dictionary).

I have a proto with an optional enumerated field such as:

enum C_TYPE
{
    AB = 0;
    BC = 1;
    CD = 2;
}

When I receive a proto with a field designated as BC everything works as I expect it. When I receive a proto with a field designated AB that field gets ignored -- it does not turn up in the python dictionary or subsequent json dump. A workaround I have found is to use json.loads(MessageToJson(protobuf, including_default_value_fields=True)) but that will create default values for all missing fields, not just the ones that have a 0 enumeration. It implies that the field with enumeration 0 is missing - but it's not!

What is the correct way to retrieve the value of the enumeration field when it is set to 0?


Solution

  • There is no correct way, I'm defining my protobufs incorrectly. For enumerated fields, the first value is the default value. This means if a protobuf comes through without a set value, it is set to the default value and, when converted to json, ignored (unless you want to keep all default values.)

    Thus, it is recommended use throw-away names for the default value to be able to properly distinguish when it has been set. i.e. I should define my protobuf as:

    enum C_TYPE
    {
        NONE = 0;
        AB = 1;
        BC = 2;
        CD = 3;
    }
    

    From Protobuf Documentation on Optional Fields And Default Values:

    For enums, the default value is the first value listed in the enum's type definition. This means care must be taken when adding a value to the beginning of an enum value list.

    Additionally from an issue on golang/protobuf:

    This is working as intended. proto3 zero-values are omitted in the JSON format too. The zero-value should be a "throwaway" value: it's also what you will see if the sender of a serialized message sets the field to an invalid or unrecognized value.