• protobuf对象与JSON相互转换


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

            
            <dependency>
                <groupId>com.google.protobufgroupId>
                <artifactId>protobuf-javaartifactId>
                <version>3.19.1version>
            dependency>
            
            <dependency>
                <groupId>com.google.protobufgroupId>
                <artifactId>protobuf-java-utilartifactId>
                <version>3.19.1version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如果不使用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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    在这里插入图片描述

    2、设置 JsonFormat处理功能

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

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

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

    在这里插入图片描述

    – 求知若饥,虚心若愚。

  • 相关阅读:
    linux常用指令
    云计算有什么作用
    【云原生】MySql索引分析及查询优化
    IEC60068-2-5太阳辐射模拟试验测试
    多图深度解析ArrayList源码
    持续集成(二)Jenkins基本使用介绍
    Linux驱动开发+QT应用编程实现IIC读取ap3216c
    【网络编程】学习成果day7:用sqlite3和fgetc将字典写入数据库中的数据表。
    Debezium系列之:Debezium Server在生产环境大规模应用详细的技术方案
    C语言——计算数组长度
  • 原文地址:https://blog.csdn.net/qq_42402854/article/details/134075140