Java 处理 protobuffers 中的空值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21227924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handling null values in protobuffers
提问by Aarish Ramesh
I am working on something which fetches data from database and constructs protobuff message. Given the possibility that null values can be fetched from the database for certain fields , I will get Null-pointer exception while trying to construct the protobuff message. Getting to know that null is not supported in protobuffs from the thread http://code.google.com/p/protobuf/issues/detail?id=57, I am wondering whether the only other way to handle NPE getting thrown is to insert manual checks into the java file corresponding to the proto like below!
我正在研究从数据库中获取数据并构建 protobuff 消息的东西。鉴于可以从数据库中获取某些字段的空值的可能性,我将在尝试构造 protobuff 消息时获得空指针异常。从线程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());
...
So can someone please clarify whether there is any other possible efficient way to handle the null values during protobuff construction??
那么有人可以澄清在protobuff构建过程中是否有任何其他可能的有效方法来处理空值?
采纳答案by Kenton Varda
There's no easy solution to this. I'd recommend just dealing with the null checks. But if you really want to get rid of them, here are a couple ideas:
对此没有简单的解决方案。我建议只处理空检查。但如果你真的想摆脱它们,这里有一些想法:
- You could write a code generator pluginwhich adds
setOrClearFoo()
methods to each Java class. The Java code generator provides insertion pointsfor this (see the end of that page). - You could use Java reflection to iterate over the
get*()
methods ofp
, call each one, check fornull
, and then call theset*()
method ofbuilder
if non-null. This will have the added advantage that you won't have to update your copy code every time you add a new field, but it will be much slower than writing code that copies each field explicitly.
回答by Michael Xin Sun
Disclaimer: Answer from a Googler using protobufs on a daily basis. I'm by no means representing Google in any way.
免责声明:来自 Google 员工每天使用 protobufs 的回答。我绝不以任何方式代表 Google。
- Name your proto
Person
instead ofPersonProto
orProtoPerson
. Compiled protobufs are just class definitions specified by the language you are using, with some improvements. Adding "Proto" is extra verbosity. - Use
YourMessage.hasYourField()
instead ofYourMessage.getYourField() != null
. Default value for protobuf string is an empty string, which does NOTequal to null. Whereas, no matter whether your field is unset or cleared or empty string,.hasYourField()
always returns false. See default values for common protobuf field types. - You've probably known, but I wanna say explicitly: Don't programmatically set a protobuf field to
null
.Even for outside of protobuf,null
causes all sorts of problems. Use.clearYourField()
instead. Person.Builder
class does NOThave a.newBuilder()
method.Person
class does. Understand the Builder Patternlike this: You create a new builder only if you do not have it yet.
- 命名您的 proto
Person
而不是PersonProto
orProtoPerson
。编译后的 protobuf 只是您使用的语言指定的类定义,并进行了一些改进。添加“Proto”是额外的冗长。 - 使用
YourMessage.hasYourField()
代替YourMessage.getYourField() != null
。protobuf 字符串的默认值为空字符串,不等于 null。然而,无论您的字段是未设置、已清除还是空字符串,.hasYourField()
都始终返回 false。查看常见 protobuf 字段类型的默认值。 - 您可能已经知道,但我想明确地说:不要以编程方式将 protobuf 字段设置为
null
. 即使在protobuf之外,也会null
导致各种问题。使用.clearYourField()
来代替。 Person.Builder
类不不有.newBuilder()
方法。Person
类。像这样理解构建器模式:只有在您还没有新构建器时才创建它。
A rewrite of your protobuf:
重写你的protobuf:
message Person {
optional firstName = 1;
optional lastName = 2;
optional address1 = 3;
}
A rewrite of your logic:
重写你的逻辑:
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();
And if thatPerson
is a person object that you created that has attribute values that could be an empty string, empty spaces or null, then I'd recommend using Guava's Strings
library:
如果thatPerson
您创建的 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();
回答by Serj-Tm
Proto 3
原型 3
wrappers.proto supports nullable values:
wrappers.proto 支持可空值:
- string(StringValue),
- int(Int32Value),
- bool(BoolValue)
- and etc
- 字符串(字符串值),
- int(Int32Value),
- 布尔(布尔值)
- 等等
Example
例子
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;
}