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 之外,所有值均已默认。