处理原始缓冲区中的空值原型 3

2022-08-31 14:32:54

我正在研究从数据库获取数据并构造protobuff消息的东西。鉴于某些字段可以从数据库中获取空值的可能性,在尝试构造protobuff消息时,我将得到空指针异常。从线程 http://code.google.com/p/protobuf/issues/detail?id=57 开始了解protobuffs中不支持null,我想知道处理NPE被抛出的唯一另一种方法是将手动检查插入到与proto相对应的java文件中,如下所示!

message ProtoPerson{
    optional string firstName = 1;
    optional string lastName = 2;
    optional string address1 = 3;
}

ProtoPerson.Builder builder = ProtoPerson.Builder.newBuilder();
if (p.getFirstName() != null) builder.setFirstName(p.getFirstName());
if (p.getLastName() != null) builder.setLastName(p.getLastName());
if (p.getAddress1() != null) builder.setAddress1(p.getAddress1());
...

那么有人可以澄清一下,在protobuff构造期间是否有任何其他可能的有效方法来处理空值?


答案 1

免责声明:Google 员工每天使用 protobufs 回答。我绝不是以任何方式代表谷歌。

  1. 将原型命名为 或 。编译的 protobufs 只是由您正在使用的语言指定的类定义,并进行了一些改进。添加“Proto”是额外的冗长。PersonPersonProtoProtoPerson
  2. 请代替 使用 。protobuf 字符串的默认值为空字符串,等于 null。然而,无论您的字段是未设置的、已清除的还是空字符串,始终返回 false。请参阅常见原型词字段类型的默认值YourMessage.hasYourField()YourMessage.getYourField() != null.hasYourField()
  3. 您可能已经知道,但我想明确地说:不要以编程方式将 protobuf 字段设置为 null即使对于原型之外,也会导致各种问题。请改用。null.clearYourField()
  4. Person.Builder没有方法。 类确实如此。像这样理解生成器模式:仅当还没有新的生成器时,才创建新的生成器。.newBuilder()Person

重写您的原型:

message Person {
  optional string first_name = 1;
  optional string last_name = 2;
  optional string address_1 = 3;
}

重写您的逻辑:

Person thatPerson = Person.newBuilder()
    .setFirstName("Aaa")
    .setLastName("Bbb")
    .setAddress1("Ccc")
    .build();

Person.Builder thisPersonBuilder = Person.newBuilder()

if (thatPerson.hasFirstName()) {
  thisPersonBuilder.setFirstName(thatPerson.getFirstName());
}

if (thatPerson.hasLastName()) {
  thisPersonBuilder.setLastName(thatPerson.getLastName());
}

if (thatPerson.hasAddress1()) {
  thisPersonBuilder.setAddress1(thatPerson.getAddress1());
}

Person thisPerson = thisPersonBuilder.build();

如果您创建的 person 对象的属性值可以是空字符串、空格或 null,那么我建议使用 Guava 的 StringsthatPerson

import static com.google.common.base.Strings.nullToEmpty;

Person.Builder thisPersonBuilder = Person.newBuilder()

if (!nullToEmpty(thatPerson.getFirstName()).trim().isEmpty()) {
  thisPersonBuilder.setFirstName(thatPerson.getFirstName());
}

if (!nullToEmpty(thatPerson.hasLastName()).trim().isEmpty()) {
  thisPersonBuilder.setLastName(thatPerson.getLastName());
}

if (!nullToEmpty(thatPerson.hasAddress1()).trim().isEmpty()) {
  thisPersonBuilder.setAddress1(thatPerson.getAddress1());
}

Person thisPerson = thisPersonBuilder.build();

答案 2

原型 3

wrappers.proto 支持可为 null 的值:

  • 字符串(字符串值),
  • int(Int32Value),
  • 布尔(布尔值)
  • 等等

syntax = "proto3";
import "google/protobuf/wrappers.proto";

message ProtoPerson {
    google.protobuf.StringValue firstName = 1;
    google.protobuf.StringValue lastName = 2;
    google.protobuf.StringValue address1 = 3;
    google.protobuf.Int32Value age = 4;
}