Skip to content

entur/numeric-fieldmask

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Numeric Protobuf Fieldmasks

TLDR: Describe FieldMasks using fieldnumbers instead of fieldnames to allow field renaming refactoring.

Why should I use FieldMasks?

Standard FieldMask operates on fieldnames. By utilizing them you also quickly loose one of the nice refactoring features of protobuf - being able to change fieldnames without breaking backwards compatibility. This is however only valid as long as you only use the binary encoding of protobuf messages, not JSON.

Please read https://stackoverflow.com/questions/69067689/why-does-protobufs-fieldmask-use-field-names-instead-of-field-numbers to understand more.

Functionality

  • Convert NumericFieldMask to FieldMasks to utilize functionality provided by FieldMaskUtil
  • Support for inverting masks, ie. specify fields to exclude instead of including (uses compiled protobuf descriptors to analyze message structures)

Use standard FieldMaskUtil operations to do actual masking operations.

Proto definition:

// Numeric field mask representing which top level fields should be returned by the server.
// Mandatory: Create this field mask using field *numbers* from the proto descriptor 
// in the generated code, not the field *name*
message NumericFieldMask {
  // Field number in message. Nested numbers allowed, use . to concatenate. 
  // Ie "1.2" will include the nested field number 2 in root message field 1
  repeated string field_number_path = 1;
  // Invert listed field paths instead of explicitly include them
  bool invert_mask = 2;
}

Example single level mask:

FieldMask onlySeconds = NumericFieldMaskUtil.toFieldMask(Timestamp.getDescriptor(),
        NumericFieldMask.newBuilder()
        .setInvertMask(true) // Invert mask
        .addFieldNumberPath(
          NumericFieldMaskUtil.buildNestedPath(Timestamp.NANOS_FIELD_NUMBER)) // Add field to include/exclude
        .build());

Example multilevel level mask:

FieldMask onlySeconds = NumericFieldMaskUtil.toFieldMask(Timestamp.getDescriptor(),
    NumericFieldMask.newBuilder()
        .addFieldNumberPath(NumericFieldMaskUtil.buildNestedPath(level1_fieldNumber, 
          level2_fieldNumber, level3_fieldNumber ...)) 
        .build());