Protobuf 序列化 反序列化

本文介绍了如何使用Protobuf定义消息格式,包括.proto文件的编写,以及在Java中使用protobuf-maven-plugin生成代码。接着展示了如何进行序列化和反序列化操作,并将结果转换为JSON格式。文章还包含了相关的Maven依赖和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Protobuf 序列化 反序列化

操作步骤

  1. 在.proto文件中定义消息格式。
  2. 使用协议缓冲区编译器。
  3. 使用Java协议缓冲区API来写入和读取消息。

.proto 文件

.proto文件以包声明开始(有助于防止不同项目之间的命名冲突)。在Java中,除非明确指定java_package,否则package将用作Java包。

java_package指定生成的类应该使用哪个java包名称。
java_outer_classname 表示该文件的类名。如果您没有显式地给出java_outer_classname,那么使用将文件名转换为大写来生成。例如,默认情况下,“my_proto.proto”会使用“MyProto”作为包装类名称。java_multiple_files=true选项允许为每个生成的类生成一个单独的.java文件。

消息申明格式如下:
phone.proto

syntax = "proto3";

package pr.iceworld.fernando.protobuf.proto;
option java_package = "pr.iceworld.fernando.protobuf.proto";
//option java_multiple_files = true;
option java_outer_classname = "PhoneProto";

message Phone {
  int32 id = 1;
  string value = 2;
  Brand brand = 3;
}

enum Brand {
  APPLE = 0;
  SAMSUNG = 1;
  HUAWEI = 2;
  MI = 3;
  reserved 4 to 19;
}

customer.proto

syntax = "proto3";

package pr.iceworld.fernando.protobuf.proto;
option java_package = "pr.iceworld.fernando.protobuf.proto";
//option java_multiple_files = true;
option java_outer_classname = "CustomerProto";

import "phone.proto";

message Customer {
  int32 id = 1;
  string name = 2;
  // enum type
  Gender gender = 3;

  // embed class
  message Address {
    int32 id = 1;
    string value = 2;
    bool default = 3;
  }

  // array
  repeated Address addresses = 4;

  Phone phone = 5;

  map<string, string> attrs = 6;
}

enum Gender {
  MALE = 0;
  FEMALE = 1;
}

pom.xml 依赖包

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>1.54.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.54.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.54.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.22.2</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.22.2</version>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.7.1</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

maven执行操作

在这里插入图片描述
在这里插入图片描述

生成的CustomerProto.java代码(片段)如下


package pr.iceworld.fernando.protobuf.proto;

public final class CustomerProto {
  private CustomerProto() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }

  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  /**
   * Protobuf enum {@code pr.iceworld.fernando.protobuf.proto.Gender}
   */
  public enum Gender
      implements com.google.protobuf.ProtocolMessageEnum {
    /**
     * <code>MALE = 0;</code>
     */
    MALE(0),
    /**
     * <code>FEMALE = 1;</code>
     */
    FEMALE(1),
    UNRECOGNIZED(-1),
    ;
// ...

序列化反序列化,同时转换为json

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;

import java.util.Arrays;

public class MainApp {

    public static void main(String[] args) {
        // builder for customer
        CustomerProto.Customer.Builder customerBuilder = CustomerProto.Customer.newBuilder();
        customerBuilder.setId(1);
        customerBuilder.setName("fernando");
        customerBuilder.setGender(CustomerProto.Gender.MALE);

        // builder for address
        CustomerProto.Customer.Address.Builder addressBuilder1 =
                CustomerProto.Customer.Address.newBuilder();
        addressBuilder1.setId(1);
        addressBuilder1.setDefault(true);
        addressBuilder1.setValue("XXXX AAAA BBBB");
        customerBuilder.addAddresses(addressBuilder1);
        // builder for address
        CustomerProto.Customer.Address.Builder addressBuilder2 =
                CustomerProto.Customer.Address.newBuilder();
        addressBuilder2.setId(2);
        addressBuilder2.setDefault(false);
        addressBuilder2.setValue("YYYY CCCCC DDDD");
        customerBuilder.addAddresses(addressBuilder2);

        // builder for phone
        PhoneProto.Phone.Builder phoneBuilder = PhoneProto.Phone.newBuilder();
        phoneBuilder.setBrand(PhoneProto.Brand.APPLE);
        phoneBuilder.setId(1);
        phoneBuilder.setValue("8610000");
        customerBuilder.setPhone(phoneBuilder);

        // attrs Map<String, String>
        customerBuilder.putAttrs("Sports", "Running");
        customerBuilder.putAttrs("Food", "Chicken");

        CustomerProto.Customer customer = customerBuilder.build();
        try {
            String toJsonOri = JsonFormat.printer().print(customer);
            System.out.println(String.format("json result=%s", toJsonOri));
            System.out.println(String.format("json size=%s", toJsonOri.getBytes().length));
            // serializable
            byte[] bytes4Customer = customer.toByteArray();
            System.out.println(String.format("bytes4Customer=%s", Arrays.toString(bytes4Customer)));
            System.out.println(String.format("bytes4Customer's length=%s", bytes4Customer.length));
            // deserializable
            CustomerProto.Customer deCustomer = CustomerProto.Customer.parseFrom(bytes4Customer);
            // can change to json format
            String toJsonDe = JsonFormat.printer().print(deCustomer);
            System.out.println(String.format("json result=%s", toJsonDe));
            System.out.println(String.format("json size=%s", toJsonDe.getBytes().length));
        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }
    }
}

输出结果

json result={
  "id": 1,
  "name": "fernando",
  "addresses": [{
    "id": 1,
    "value": "XXXX AAAA BBBB",
    "default": true
  }, {
    "id": 2,
    "value": "YYYY CCCCC DDDD"
  }],
  "phone": {
    "id": 1,
    "value": "8610000"
  },
  "attrs": {
    "Sports": "Running",
    "Food": "Chicken"
  }
}
json size=293
bytes4Customer=[8, 1, 18, 8, 102, 101, 114, 110, 97, 110, 100, 111, 34, 20, 8, 1, 18, 14, 88, 88, 88, 88, 32, 65, 65, 65, 65, 32, 66, 66, 66, 66, 24, 1, 34, 19, 8, 2, 18, 15, 89, 89, 89, 89, 32, 67, 67, 67, 67, 67, 32, 68, 68, 68, 68, 42, 11, 8, 1, 18, 7, 56, 54, 49, 48, 48, 48, 48, 50, 17, 10, 6, 83, 112, 111, 114, 116, 115, 18, 7, 82, 117, 110, 110, 105, 110, 103, 50, 15, 10, 4, 70, 111, 111, 100, 18, 7, 67, 104, 105, 99, 107, 101, 110]
bytes4Customer's length=104
json result={
  "id": 1,
  "name": "fernando",
  "addresses": [{
    "id": 1,
    "value": "XXXX AAAA BBBB",
    "default": true
  }, {
    "id": 2,
    "value": "YYYY CCCCC DDDD"
  }],
  "phone": {
    "id": 1,
    "value": "8610000"
  },
  "attrs": {
    "Sports": "Running",
    "Food": "Chicken"
  }
}
json size=293
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值