I couldnt find a way to mask certain fields in protobuf structure. I did read about the FieldMaskUtil and tried few examples but it seems to do the reverse i.e copy fields which are mentioned in FieldMask which is different from what i wanted. Here's the sample structure and corresponding Test code.
Proto:
syntax = "proto3";
package model;
option java_package = "test.demo.services.protobuf.customer.model";
option java_outer_classname = "CustomerProto";
message Accounts {
repeated Account account = 1;
}
message Account {
int32 id = 1;
string number = 2;
int32 customer_id = 3;
}
message Customers {
repeated Customer customers = 1;
}
message Customer {
int32 id = 1;
string pesel = 2;
string name = 3;
CustomerType type = 4;
repeated Account accounts = 5;
enum CustomerType {
INDIVIDUAL = 0;
COMPANY = 1;
}
}
Here's sample test code
package test.demo.services.protobuf.customer.model;
import org.junit.Test;
import test.demo.services.protobuf.customer.model.CustomerProto.Customer;
import com.google.protobuf.util.FieldMaskUtil;
public class TestMerge {
@Test
public void eraseFields() {
Customer request = Customer.newBuilder().setId(10).setPesel("12345").setName("Harry Alto").build();
// Erase name
Customer.Builder modifieldRequest = Customer.newBuilder();
FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), request, modifieldRequest);
System.out.println( modifieldRequest.build().toString());
}
}
Here's the output:
name: "Harry Alto"
What i would have expected is to print everything other than name
id: 10
pesel: "12345"
Is there a way to do what i want
FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), request, modifieldRequest);
What i would have expected is to print everything other than name
No, according to the JavaDocs for FieldMask
, the behavior is opposite of what you described:
Field masks are used to specify a subset of fields that should be returned by a get operation or modified by an update operation.
The mask acts as as a set intersection operation, selecting only fields that were specified. In your case, the mask specifies only "name", so that is what it selects.
The behavior you are seeking is really a set complement operation, selecting all fields that were not specified. I'm not aware of a built-in method in the Protobuf API to do this. Options for implementing this yourself are:
FieldMask
instances using a separate call to FieldMask#fromString
for each named field that you want to retain. Then, use FieldMaskUtil#union
to combine all of them. This will retain only the specifically listed fields. If you evolve the schema later to add more fields, then it won't pick up those new fields. You'd have to change the code and add the new named fields into that union.MessageOrBuilder#getAllFields
to get a descriptor for all fields in the message. Iterate through all of them, using FieldMaskUtil#union
as described above, but skip specific fields that you want to ignore, like "name". If you evolve the schema later to add more fields, then this will pick up those new fields. You won't need to change the code to start including those new fields.Note the differences with respect to schema evolution in those solutions. The choice of which one is most appropriate depends on your requirements.