Protocol Buffers - 可选字段与默认值



概述

我们已经了解了各种数据类型及其使用方法。如果在序列化时未指定值会发生什么?“proto2”版本支持“required”“optional”标签,这有助于确定如果所需的解析逻辑不可用,序列化/反序列化是否应该失败。但是,“required”标签在“proto3”版本中已移除。失败部分需要由相应的代码处理。现在每个属性都是可选的,并具有默认值。因此,从“proto3”版本开始,“optional”的使用是多余的。

Protocol Buffers根据下表支持其数据类型的默认值:

数据类型 默认值
Int32 / Int64 0
Float/double 0.0
字符串 空字符串
布尔值 False
枚举 第一个枚举项,即“index=0”的项
重复类型 空列表
Map 空Map
嵌套类 null

因此,如果未为这些数据类型指定数据,则它们将采用上述默认值。现在,让我们继续我们的theater示例来演示其工作原理。

在这个例子中,我们将让所有字段使用默认值。唯一指定的字段将是剧院的名称。

继续我们来自Protocol Buffers - 字符串章节的theater示例,以下是我们需要使用的语法,以指示 Protobuf 我们将创建不同的数据类型:

theater.proto

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;
}

现在我们的message类包含多个属性。

从Proto文件创建Java类

要使用 Protobuf,我们现在必须使用protoc二进制文件从此“.proto”文件创建所需的类。让我们看看如何做到这一点:

protoc  --java_out=. theater.proto

这将在当前目录的com > tutorialspoint > theater文件夹中创建一个TheaterOuterClass.java类。我们在应用程序中使用此类,类似于Protocol Buffers - 基本应用章节中所做的那样。

使用从Proto文件创建的Java类

TheaterWriter.java

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: \n" + theater);
   }
}

接下来,我们将有一个reader来读取theater信息:

TheaterReader.java

package com.tutorialspoint.theater;

import java.io.FileInputStream;
import java.io.IOException;

import com.tutorialspoint.theater.TheaterOuterClass.Theater;
import com.tutorialspoint.theater.TheaterOuterClass.Theater.Builder;

public class TheaterReader{
   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() + "\n" +
            "Address:" + theater.getAddress() + "\n" +
            "Drive_In:" + theater.getDriveIn() + "\n" +
            "Total Capacity:" + theater.getTotalCapcity() + "\n" +
            "Base Ticket Prices: " + theater.getBaseTicketPrice() + "\n" +
            "Owner: " + theater.getOwner() + "\n" +
            "Snacks: " + theater.getSnacksList() + "\n" +
            "Payment: " + theater.getPayment()
         );
            
         //Map<FieldDescriptor, Object> f = theater.getAllFields();
         System.out.println("List of fields explicitly specified: " + theater.getAllFields());
      }
   }
}

编译项目

现在我们已经设置了readerwriter,让我们编译项目。

mvn clean install

序列化Java对象

现在,编译后,让我们首先执行writer

> java -cp .\target\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 .\target\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之外,所有值都相应地使用了默认值。

广告
© . All rights reserved.