首页 前端知识 protobuf对象与JSON相互转换

protobuf对象与JSON相互转换

2024-06-20 09:06:14 前端知识 前端哥 830 156 我要收藏

除了之前的 protobuf-java依赖之外,还需要引入 protobuf-java-uti 依赖:

        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.19.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.19.1</version>
        </dependency>

如果不使用protobuf提供的JSON API,而使用fastJson等,直接序列化 com.google.protobuf.Message proto对象,会报错。如果希望使用第三方的JSON API,可以重新定义一个实体类,抽取需要的字段。

一、注意默认值

官网文档:https://protobuf.dev/programming-guides/proto3/#default

在这里插入图片描述

官方字段默认值,使用时需要注意:

  1. 对于标量消息字段,一旦解析了消息,就无法判断字段是显式设置为默认值还是根本没有设置(例如布尔值是否设置为false):所以,在定义消息类型时应该记住这一点。例如,如果你不希望某些行为在默认情况下也发生,不要使用布尔值在设置为false时打开某些行为。
  2. 如果将标量消息字段设置为其默认值(显式设置),则该值将不会在网络上序列化。
  3. Json 转 proto 对象时,如果Json字符串中的设置为了默认值(显式设置),则该值将不会在网络上序列化。

1、protobuf对象 转 JSON串

// 接收数据反序列化:将字节数据转化为对象数据。
UserProtoBuf.User user = UserProtoBuf.User.parseFrom(byteData);

// 1、proto 对象 转 Json
//获取 Printer对象用于生成JSON字符串
JsonFormat.Printer printer = JsonFormat.printer();
String userJsonStr = printer.print(user);

Printer对象生成 JSON字符串时,支持设置一些功能方法。比如:

  • includingDefaultValueFields():表示 Json输出包含默认值(显示和隐式赋默认值)的字段。
  • preservingProtoFieldNames():表示使用.proto文件中定义的原始proto字段名而不是将其转换为lowerCamelCase输出。默认 lowerCamelCase的输出。

2、JSON串 转 protobuf对象

// 创建 proto 对象
UserProtoBuf.User.Builder userBuilder = UserProtoBuf.User.newBuilder();

// 2、Json 转 proto 对象
//获取 Parser对象用于解析JSON字符串
JsonFormat.Parser parser = JsonFormat.parser();
parser.merge(userJsonStr2, userBuilder);

Parser对象解析 JSON字符串时,支持设置一些功能方法。比如:

  • ignoringUnknownFields():表示如果 json 串中存在的属性,proto 对象中不存在,则进行忽略,否则会抛出 InvalidProtocolBufferException异常。

二、示例实战

proto文件内容如下:

syntax = "proto3";

//生成 proto java文件名(一般指定,文件名+自定义。如果不指定,默认时文件名+OuterClass)
option java_outer_classname = "UserProtoBuf";

message User {

  int32 age = 1;
  int64 timestamp = 2;
  bool enabled = 3;
  float height = 4;
  double weight = 5;
  string userName = 6;
  string Full_Address = 7;

}

1、使用 JsonFormat默认功能

import com.google.protobuf.util.JsonFormat;

public class UserTest {

    public static void main(String[] args) throws Exception {

        // 将数据序列化
        byte[] byteData = getClientPush();
        System.out.println("获取到字节数据:byteData长度=" + byteData.length);
        System.out.println("===========");

        /**
         * 接收数据反序列化:将字节数据转化为对象数据。
         */
        UserProtoBuf.User user = UserProtoBuf.User.parseFrom(byteData);
        System.out.println("==== get获取 user信息:=======");
        System.out.println("user信息:     \n" + user);
        System.out.println("------------------");
        System.out.println("getAge=         " + user.getAge());
        System.out.println("getTimestamp=   " + user.getTimestamp());
        System.out.println("getEnabled=     " + user.getEnabled());
        System.out.println("getHeight=      " + user.getHeight());
        System.out.println("getWeight=      " + user.getWeight());
        System.out.println("getUserName=        " + user.getUserName());
        System.out.println("getFullAddress= " + user.getFullAddress());


        /**
         * proto 对象 转 Json互转
         */
        // 1、proto 对象 转 Json
        String userJsonStr = JsonFormat.printer()
                //.includingDefaultValueFields() // 表示 Json输出包含默认值(显示和隐式赋默认值)的字段。
                .print(user);
        System.out.println("=====1、proto对象 转 Json字符串:======");
        System.out.println("userJsonStr=    " + userJsonStr);

        // 2、Json 转 proto 对象
        String userJsonStr2 = "{\n" +
                "    \"age\":18,\n" +
                "    \"timestamp\":\"1698377283315\",\n" +
                "    \"enabled\":false,\n" +
                "    \"height\":1.8,\n" +
                "    \"weight\":66.76,\n" +
                "    \"userName\":\"赵云\"\n" +
                "}";
        // 创建 proto 对象
        UserProtoBuf.User.Builder userBuilder = UserProtoBuf.User.newBuilder();
        JsonFormat.parser()
                //.ignoringUnknownFields() // 表示如果 json 串中存在的属性,proto 对象中不存在,则进行忽略,否则会抛出 InvalidProtocolBufferException异常
                .merge(userJsonStr2, userBuilder);

        UserProtoBuf.User user1 = userBuilder.build();
        System.out.println("=====2、Json 转 proto 对象:======");
        System.out.println("user1信息:        \n" + user1);
        System.out.println("------------------");
    }

    /**
     * 模拟发送方,将数据序列化后发送
     *
     * @return
     */
    private static byte[] getClientPush() {
        // 按照定义的数据结构,创建一个对象。
        UserProtoBuf.User.Builder user = UserProtoBuf.User.newBuilder();
        user.setAge(18);
        user.setTimestamp(System.currentTimeMillis());
        user.setEnabled(false);
        //user.setEnabled(true);
        //user.setHeight(1.88F);
        user.setWeight(66.76D);
        user.setUserName("赵云");
        //user.setFullAddress("王者-打野");

        /**
         * 发送数据序列化:将对象数据转化为字节数据输出
         */
        UserProtoBuf.User userBuild = user.build();
        byte[] bytes = userBuild.toByteArray();
        return bytes;
    }

}

在这里插入图片描述

2、设置 JsonFormat处理功能

这里使用 JsonFormat的这两个方法。其他方法自行查看。

  • Printer对象使用 includingDefaultValueFields()方法。
  • Parser对象使用 ignoringUnknownFields()方法。

将上面这两个方法的注释打开,运行结果如下:

在这里插入图片描述

– 求知若饥,虚心若愚。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/13020.html
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!