【问题标题】:How to Mask certain fields in Protobuf如何屏蔽 Protobuf 中的某些字段
【发布时间】:2017-08-03 07:31:51
【问题描述】:

我找不到屏蔽 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"

有没有办法做我想做的事

【问题讨论】:

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


    【解决方案1】:
    FieldMaskUtil.merge(FieldMaskUtil.fromString("name"), request, modifieldRequest);
    

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

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

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

    掩码充当集合交集操作,仅选择指定的字段。在您的情况下,掩码仅指定“名称”,这就是它选择的内容。

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

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

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

    【讨论】:

    • 感谢@cnauroth 的澄清。感谢您提出的解决方案。会试试的。
    • 如果您有一个客户 protobuf 并且想要屏蔽每个客户的每个 protobuf 中的名称字段怎么办?我不确定如何处理重复的字段。
    • 如果我想在序列化 protobuf 时屏蔽字段怎么办?
    【解决方案2】:

    如果你真的想删除姓名字段,你可以这样做:

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

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

    【讨论】:

    • 如果我想在序列化 protobuf 时屏蔽字段怎么办?
    猜你喜欢
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 2019-08-22
    • 2021-09-25
    相关资源
    最近更新 更多