如何掩盖Protobuf中的某些字段

时间:2017-07-27 16:06:08

标签: java protocol-buffers protocol-buffers-3

我无法找到掩盖protobuf结构中某些字段的方法。我确实阅读了有关FieldMaskUtil的内容,并尝试了一些示例,但它似乎做了反向,即FieldMask中提到的复制字段,这与我想要的不同。这是样本结构和相应的测试代码。

原:

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;
  }

}

此处的示例测试代码

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());
}

}

这是输出:

name: "Harry Alto"

我所期望的是打印名称以外的所有内容

id: 10
pesel: "12345"

有办法做我想做的事吗

2 个答案:

答案 0 :(得分:2)

FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), request, modifieldRequest);
  

我所期望的是打印名称以外的所有内容

不,根据FieldMask的JavaDocs,行为与你所描述的相反:

  

字段掩码用于指定应该是的字段子集   由get操作返回或由更新操作修改。

掩码用作集交集操作,仅选择已指定的字段。在您的情况下,掩码仅指定“名称”,因此它就是它所选择的。

您正在寻找的行为实际上是一组补充操作,选择未指定的所有字段。我不知道Protobuf API中的内置方法可以做到这一点。自己实现这个的选项是:

  • 为每个要保留的命名字段单独调用FieldMask构建多个FieldMask#fromString实例。然后,使用FieldMaskUtil#union将所有这些组合起来。这将仅保留特定列出的字段。如果您稍后进化模式以添加更多字段,那么它将不会获取这些新字段。您必须更改代码并将新的命名字段添加到该联合中。
  • 调用MessageOrBuilder#getAllFields获取消息中所有字段的描述符。使用上面描述的FieldMaskUtil#union迭代所有这些内容,但跳过您要忽略的特定字段,例如“name”。如果您稍后进化模式以添加更多字段,那么这将获取这些新字段。您无需更改代码即可开始包含这些新字段。

请注意这些解决方案中与模式演变的差异。选择哪一种最合适取决于您的要求。

答案 1 :(得分:0)

如果您真的想要删除名称字段,可以这样做:

Customer.Builder request Customer.newBuilder()
    .setId(10).setPesel("12345").setName("Harry Alto").build();
// Erase name
Customer.Builder modifiedRequest = request.toBuilder();
Customer modifyRequest = Customer.getDefaultInstance();
FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), modifyRequest, modifiedRequest);
System.out.println(modifiedRequest.build().toString());

这应该会产生你想要的结果。