处理protobuffers中的空值

Aar*_*esh 35 java null protocol-buffers

我正在研究从数据库中获取数据并构造protobuff消息的东西.鉴于可以从数据库中为某些字段提取空值,我将在尝试构造protobuff消息时获得Null指针异常.从线程http://code.google.com/p/protobuf/issues/detail?id=57中的protobuffs中不支持知道null ,我想知道处理NPE的唯一其他方法是抛出是将手动检查插入到与原型相对应的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());
...
Run Code Online (Sandbox Code Playgroud)

那么有人可以澄清在protobuff构造期间是否还有其他可行的有效方法来处理空值?

Mic*_*Sun 42

免责声明:每天使用protobufs从Google播放器中回答.我决不以任何方式代表谷歌.

  1. 为你的原型命名Person而不是PersonProtoProtoPerson.编译的protobufs只是您正在使用的语言指定的类定义,并有一些改进.添加"Proto"是额外的冗长.
  2. YourMessage.hasYourField()而不是YourMessage.getYourField() != null.对于protobuf的字符串缺省值是一个空字符串,这确实等于空.然而,无论您的字段是未设置或清除还是空字符串,.hasYourField()始终返回false.请参阅常用protobuf字段类型的默认值.
  3. 您可能已经知道了,但我想明确地说:不要以编程方式将protobuf字段设置为null.即使对于protobuf之外,也会null 引起各种各样的问题.请.clearYourField()改用.
  4. Person.Builder类不.newBuilder()方法.Person上课.像这样理解Builder模式:只有在没有它的情况下才创建新的构建器.

重写你的protobuf:

message Person {
  optional firstName = 1;
  optional lastName = 2;
  optional address1 = 3;
}
Run Code Online (Sandbox Code Playgroud)

重写你的逻辑:

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();
Run Code Online (Sandbox Code Playgroud)

如果thatPerson你创建的人物对象的属性值可以是空字符串,空格或空,那么我建议使用Guava的Strings:

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();
Run Code Online (Sandbox Code Playgroud)

  • 你的帖子可能充满了好的建议......但我不确定你是否理解他的问题?例如,他的数据不是来自另一个protobuf对象; 它来自数据库或其他来源,可能有空值.他基本上想知道如何轻松处理空值. (21认同)
  • 这个答案是否与问题中的建议相同 - 仅使用空检查?相关部分 - 回答问题的部分仅在最后一段。令人困惑的是,答案的另一部分是回答尚未提出的问题。 (4认同)
  • 好点 Erhannis,谢谢。我通过添加一个部分来处理具有空字符串值、连续空间值和空值的非协议缓冲区对象来更新答案。 (2认同)

Ser*_*-Tm 27

原型 3

wrappers.proto 支持可空值:

  • 字符串(字符串值),
  • 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 完整列表位于 https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/protobuf-data-types#nullable-types (2认同)

Ken*_*rda 11

对此没有简单的解决方案.我建议只处理空检查.但如果你真的想摆脱它们,这里有几个想法:

  • 您可以编写一个代码生成器插件,setOrClearFoo()为每个Java类添加方法.Java代码生成器为此提供插入点(请参阅该页面的末尾).
  • 您可以使用Java反射来迭代get*()方法p,调用每个方法,检查null,然后调用if非null 的set*()方法builder.这将具有额外的优势,即每次添加新字段时都不必更新复制代码,但它比编写明确复制每个字段的代码要慢得多.