Java 如何屏蔽Protobuf中的某些字段

Java 如何屏蔽Protobuf中的某些字段,java,protocol-buffers,protocol-buffers-3,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_classna

我找不到一种方法来屏蔽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"
有没有办法做我想做的事

FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), request, modifieldRequest);
我所期望的是打印除姓名以外的所有内容

id: 10
pesel: "12345"
不,根据JavaDocs for,行为与您描述的相反:

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

遮罩充当集合相交操作,仅选择指定的字段。在您的例子中,掩码只指定“名称”,因此它选择的是“名称”

您正在寻找的行为实际上是一个集合补码操作,选择所有未指定的字段。我不知道protobufapi中有内置的方法来实现这一点。可自行实施的选项有:

  • 为要保留的每个命名字段分别调用
    FieldMask#fromString
    ,构造多个
    FieldMask
    实例。然后,使用将它们组合在一起。这将只保留特定列出的字段。如果您以后对模式进行改进以添加更多字段,那么它将不会选择这些新字段。您必须更改代码并将新的命名字段添加到该联合中
  • 调用以获取消息中所有字段的描述符。如上所述,使用
    FieldMaskUtil#union
    遍历所有字段,但跳过要忽略的特定字段,如“name”。如果您以后对模式进行改进以添加更多字段,那么这将拾取这些新字段。您无需更改代码即可开始包含这些新字段

请注意这些解决方案在模式演化方面的差异。选择哪一个最合适取决于您的要求。

如果您确实希望删除名称字段,您可以这样做:

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

这将产生您想要的结果。

感谢@cnauroth的澄清。感谢您提出的解决方案。将尝试。如果您有一个Customers protobuf并希望在每个Customer中的每个protobuf中屏蔽名称字段,该怎么办?我不知道如何处理重复的字段。如果我想在序列化protobuf时屏蔽字段呢?如果我想在序列化protobuf时屏蔽字段呢?