Protobuf - Optionality & Defaults
虽然我们研究了各种数据类型及其使用方法。如果我们在序列化时不指定值会发生什么?Google Protobuf 2 支持"required"和"optional"标签,这有助于确定如果所需的解析逻辑不可用,序列化/反序列化是否会失败。但这些标签在最新版本中不可用。失败的部分需要由相应的代码处理。
让我们看看数据类型的默认值 −
| 数据类型 | 默认值 |
|---|---|
| Int32 / Int64 | 0 |
| Float/double | 0.0 |
| String | 空字符串 |
| Boolean | False |
| Enum | 第一个 Enum 项,即"index=0"的项 |
| 重复类型 | 空列表 |
| Map | 空 Map |
| 嵌套类 | null |
因此,如果没有为这些数据类型指定数据,则它们将采用上述默认值。现在,让我们继续使用 剧院 示例来演示其工作原理。
在此示例中,我们将让所有字段都为默认。唯一需要指定的字段是剧院的名称。
syntax = "proto3";
package theater;
option java_package = "com.tutorialspoint.theater";
message Theater {
string name = 1;
string address = 2;
int32 total_capcity = 3;
int64 mobile = 4;
float base_ticket_price = 5;
bool drive_in = 6;
enum PAYMENT_SYSTEM {
CASH = 0;
CREDIT_CARD = 1;
DEBIT_CARD = 2;
APP = 3;
}
PAYMENT_SYSTEM payment = 7;
repeated string snacks = 8;
map<string, int32> movieTicketPrice = 9;
TheaterOwner owner = 10;
}
message TheaterOwner{
string name = 1;
string address = 2;
}
现在我们的 class/message 包含多个属性。要使用 Protobuf,我们必须使用 protoc 二进制文件从此".proto"文件创建所需的类。让我们看看如何做到这一点 −
protoc --java_out=java/src/main/java proto_files heater.proto
上述命令应该创建所需的文件,现在我们可以在 Java 代码中使用它。首先,让我们创建一个 writer 来写入 theater 信息 −
package com.tutorialspoint.theater;
import java.io.FileOutputStream;
import java.io.IOException;
import com.tutorialspoint.theater.TheaterOuterClass.Theater;
public class TheaterWriter {
public static void main(String[] args) throws IOException {
Theater theater = Theater.newBuilder()
.setName("SilverScreen")
.build();
String filename = "theater_protobuf_output";
System.out.println("Saving theater information to file: " + filename);
try(FileOutputStream output = new FileOutputStream(filename)){
theater.writeTo(output);
}
System.out.println("Saved theater information with following data to disk:
" + theater);
}
}
接下来,我们将有一个reader(阅读器)来读取theater(剧院)的信息 −
package com.tutorialspoint.theater;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.tutorialspoint.greeting.Greeting.Greet;
import com.tutorialspoint.theater.TheaterOuterClass.Theater;
import com.tutorialspoint.theater.TheaterOuterClass.Theater.Builder;
public class TheaterReaderExplicit{
public static void main(String[] args) throws IOException {
Builder theaterBuilder = Theater.newBuilder();
String filename = "theater_protobuf_output";
System.out.println("Reading from file " + filename);
try(FileInputStream input = new FileInputStream(filename)) {
Theater theater = theaterBuilder.mergeFrom(input).build();
System.out.println(
"Name:" + theater.getName() + "
" +
"Address:" + theater.getAddress() + "
" +
"Drive_In:" + theater.getDriveIn() + "
" +
"Total Capacity:" + theater.getTotalCapcity() + "
" +
"Base Ticket Prices: " + theater.getBaseTicketPrice() + "
" +
"Owner: " + theater.getOwner() + "
" +
"Snacks: " + theater.getSnacksList() + "
" +
"Payment: " + theater.getPayment()
);
//Map<FieldDescriptor, Object> f = theater.getAllFields();
System.out.println("List of fields explicitly specified: " + theater.getAllFields());
}
}
}
现在,编译后,让我们首先执行writer −
> java -cp . arget\protobuf-tutorial-1.0.jar com.tutorialspoint.theater.TheaterWriter Saving theater information to file: theater_protobuf_output Saved theater information with following data to disk: name: "SilverScreen"
现在,让我们执行 reader 来读取同一个文件 −
java -cp . arget\protobuf-tutorial-1.0.jar com.tutorialspoint.theater.TheaterReader
Reading from file theater_protobuf_output
Name:SilverScreen
Address:
Drive_In:false
Total Capacity:0
Base Ticket Prices: 0.0
Owner:
Snacks: []
Payment: CASH
List of fields explicitly specified: {theater.Theater.name=SilverScreen}
因此,如我们所见,除了最底行中我们明确指定的 name 之外,所有值均已默认。

