处理protobuffers中的空值

时间:2014-01-20 06:58:05

标签: 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());
...

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

3 个答案:

答案 0 :(得分:42)

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

  1. 为您的原型Person而不是PersonProtoProtoPerson命名。编译的protobufs只是您正在使用的语言指定的类定义,并有一些改进。添加“Proto”是额外的冗长。
  2. 使用YourMessage.hasYourField()代替YourMessage.getYourField() != null。 protobuf字符串的默认值是一个空字符串, NOT 等于null。然而,无论您的字段是未设置或清除还是空字符串,.hasYourField()始终返回false。见default values for common protobuf field types
  3. 您可能已经知道了,但我想明确地说:不要以编程方式将protobuf字段设置为null即使对于protobuf之外,null {{ 3}}。请改用.clearYourField()
  4. Person.Builder NOT .newBuilder()方法。 Person课程。像这样理解 Builder模式:只有在没有它的情况下才创建新的构建器。
  5. 重写你的protobuf:

    message Person {
      optional firstName = 1;
      optional lastName = 2;
      optional address1 = 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();
    

    如果thatPerson是您创建的人物对象,其属性值可以是空字符串,空格或空,那么我建议使用causes all sorts of problems

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

答案 1 :(得分:17)

Proto 3

wrappers.proto支持可为空的值:

  • string(StringValue),
  • int(Int32Value),
  • bool(BoolValue)
  • 等等

示例

#client
import socket

HOST_IP = '127.0.0.1'
DEST_PORT = 1731

my_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

my_socket.connect((HOST_IP,DEST_PORT))

data1 = "test1"
print("client send")
my_socket.sendall(data1.encode())
my_socket.sendall("second send ".encode())

my_socket.close()

答案 2 :(得分:9)

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

  • 您可以编写code generator plugin,为每个Java类添加setOrClearFoo()个方法。 Java代码生成器为此提供insertion points(参见该页末尾)。
  • 您可以使用Java反射来迭代get*()的{​​{1}}方法,调用每个方法,检查p,然后调用null方法set*() 1}}如果非null。这将具有额外的优势,即每次添加新字段时都不必更新复制代码,但它比编写明确复制每个字段的代码要慢得多。