当前位置: 首页 > 知识库问答 >
问题:

处理protobuffers中的null值

诸葛雅达
2023-03-14

我正在研究从数据库中获取数据并构建协议buff消息的东西。鉴于某些字段可以从数据库中获取空值的可能性,我将在尝试构建协议buff消息时获得空指针异常。了解到线程http://code.google.com/p/protobuf/issues/detail?id=57的原型不支持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个答案

章安宜
2023-03-14

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

  • 您可以编写一个代码生成器插件,将setOrClearFoo()方法添加到每个Java类中。Java代码生成器为此提供了插入点(请参见该页的末尾)
  • 您可以使用Java反射来迭代p的get*()方法,调用每个方法,检查null,然后调用builder的set*()方法(如果非null)。这样做的另一个好处是,您不必每次添加新字段时都更新复制代码,但这比编写显式复制每个字段的代码要慢得多

巫马盛
2023-03-14

wrappers.proto支持空值:

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

实例

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;
}
唐兴思
2023-03-14

免责声明:每日使用protobufs的Googler提供的答案。我绝不代表谷歌。

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

重写您的protobuf:

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

如果that Person是您创建的一个人对象,其属性值可以是空字符串、空格或null,那么我建议使用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();
 类似资料:
  • 问题内容: 这是我用于通过DataReader从sql读取数据的代码。当表中有NULL时,它将给出错误。怎么处理呢? 我试过了 问题是它可以成功处理NULL,但是即使sql数据库在该字段中的值为1,结果也始终为0。 问题答案: 您可以用来从数据读取器中检查空值。C#和有所不同。

  • 问题内容: 我是Derby的新手,我注意到,就值而言,我面临着与使用DB2 RDBMS时类似的问题。Derby文档指出,值必须具有与之关联的类型(DB2最终在9.7版中被删除): http://db.apache.org/derby/docs/10.7/ref/crefsqlj21305.html 现在,我试图在这里找到解决此问题的 一般 方法,因为这将成为我的数据库抽象库jOOQ的一部分。下面的

  • 问题内容: 我想比较两列中的两个日期并得到最大值,然后再与日期值进行比较。这两列也可以容纳NULL值,例如我想要下面的OUTPUT。如何使用最大的函数或是否有任何东西else。我再次使用输出与另一个日期进行比较。 问题答案: 在您的选择中使用Oracle结构:

  • 问题内容: 我有以下代码: 然后,我尝试: 返回行抛出错误: {“将值\“ \”转换为类型’System.Double’时出错。“} 在线上有许多解决方案建议使用空值类型创建自定义,但这对我不起作用。我不能指望json是某种格式。我无法控制列数,列类型或列名。 问题答案: 您可以提供设置来告诉它如何处理空值(在这种情况下,还有更多):

  • 问题内容: 我有一个LoginForm组件。我要检查之前提交,这两个和设置。我尝试使用此代码(省略了很多内容): 但是,我在事件处理程序中得到一个,说是空的。 我该怎么办? 问题答案: 你需要设置的方法,因为现在是,对于此操作,您可以使用 或者您可以使用箭头功能