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