protobuf2 java版

protobuf 2

定义一个消息

## protobuf 2

syntax = "proto2";  // 该文件的第一行指定您正在使用 proto2 语法。 这应该是文件的第一个非空、非注释行。

//required:一个格式良好的消息一定要含有1个这种字段。表示该值是必须要设置的;
//optional:消息格式中该字段可以有0个或1个值(不超过1个)。
//repeated:在一个格式良好的消息中,这种字段可以重复任意多次(包括0次)。相当于java中的List。

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  repeated int32 result_per_page = 3;
}

编号:

1 ~ 536870911(除去 19000 到 19999 之间的标识号, Protobuf 协议实现中对这些进行了预留。如果非要在.proto 文件中使用这些预留标识号,编译时就会报警)

在消息定义中,每个字段都有唯一的一个标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改 变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该尽可能为那些频繁出现的消息元素保留 [1,15]之内的标识号。

protobuf类型java类型默认值
doubledouble0
floatfloat0
int32int0
int64long0
boolbooleanfalse
stringString“”

对于字符串,默认值为空字符串。 对于字节,默认值为空字节字符串。 对于布尔值,默认值为 false。 对于数字类型,默认值为零。 对于枚举,默认值是枚举类型定义中列出的第一个值。 这意味着在向枚举值列表的开头添加值时必须小心。可以通过default关键字改变默认值。

syntax = "proto2";

// package定义了该.proto文件的命名空间, 定义该属性不会对java类的输出目录产生影响,
// 但是会影响java类能否生成:定义了package后,可以生成两个属性完全一样的java文件(即两个proto文件只有message的名称和java_outer_classname不一样,其他完全一样)
// package只是定义命名空间,可以n个proto文件都定义相同的package,也可以不同(如果想要两个proto仅仅是java_outer_classname不一样,其他完全一样,就必须定义不同的命名空间)。如果想在两个proto文件中定义相同的enum,package必须不同(若不指明不同的package,即使两个proto文件仅仅是enum里的属性相同,其他完全不同,也是不能生成java文件的)
package org.example;

option java_package = "org.example.me";     // 输出java类所在目录

option java_outer_classname = "EnumTestMulti";    // 输出java类的名称为EnumTestMulti.java

// 是否输出多个java类,设置为true将根据message输出多个java类文件,设置为false一个proto文件只会输出一个java文件
option java_multiple_files = false;  

message TestMulti {
  optional string a = 1 [default = "aaa"];
  optional int32 b = 2;
  optional int64 c = 3;
  optional bool d = 4;
  optional float e = 5;
  optional double f = 6;
  repeated int64 g = 7;
  required typeA2C t = 8 [default = B];
  // key_type 可以是任何整数或字符串类型(即除了浮点数和bytes类型)。请注意,枚举不是有效的 key_type。value_type 可以是除 map 之外的任何类型
  // maps 不能是 repeated、optional、required
  map<string, int32> h = 9;
}

enum typeA2C {
  A = 0;
  B = 1;
  C = 2;
}

消息嵌套和引用

syntax = "proto2";

package org.example;

import "importTest.proto";

option java_package = "org.example";

option java_outer_classname = "NestedMulti";

option java_multiple_files = false;

message Foo {
  optional int32 val = 1;
  optional immTest tt = 2;
}

message Bar {
  optional Foo foo = 1;
}

message Baz {
  optional Bar bar = 1;
}
syntax = "proto2";

package org.example;

option java_package = "org.example";

option java_outer_classname = "ImmTestDemo";

option java_multiple_files = false;

message immTest {
  optional int32 abc = 1;
}

生成java类命令

# 不存在proto文件的相互import时可以这样生成    exe + 要生成java的proto文件路径 + java文件路径  
./protoc-3.12.0-windows-x86_64.exe ./HelloWorld.proto --java_out=./
# 存在互相import时,必须用--proto_path指明要搜索import的proto文件路径  exe + import的proto文件路径 + java文件路径 + 要生成java的proto文件路径
 ./proto/protoc-3.12.0-windows-x86_64.exe --proto_path=./proto --java_out=./java ./proto/*.proto

代码示例

package org.example;

import com.google.protobuf.util.JsonFormat;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;

public class App {
    public static void main( String[] args ) {
        EnumTestMulti.TestMulti.Builder TestMultibuilder = EnumTestMulti.TestMulti.newBuilder();
        EnumTestMulti.TestMulti message = TestMultibuilder.setA("a").setB(2).setC(3L).setD(true).setE(0.1f).setF(4D).addG(5L)
                .setT(EnumTestMulti.typeA2C.B).putH("HKey", 6).build();

        // 序列化
        byte[] bytes = message.toByteArray();
        // 反序列化
        try {
            /**
             * parseFrom: 可以从ByteBuffer, InputStream, byte[]等反序列化
             */
            EnumTestMulti.TestMulti testMulti = EnumTestMulti.TestMulti.parseFrom(bytes);
            System.out.println("=======================打印消息==============================");
            //嵌套builder
            System.out.println(testMulti);
        } catch (Exception e) {
            // TODO
        }
        // 将消息写到输出流
        OutputStream outputStream = new ByteArrayOutputStream();
        try {
            message.writeTo(outputStream);
        } catch (Exception e) {
            // TODO
        }
        System.out.println("=======================嵌套builder==============================");
        //嵌套builder
        NestedMulti.Foo foo = NestedMulti.Baz.newBuilder().getBarBuilder().getFooBuilder().setVal(100)
                // 设置import消息的值
                .setTt(ImmTestDemo.immTest.newBuilder().setAbc(888))
                .build();
        System.out.println(foo);
        System.out.println("=========================mergeFrom============================");
        EnumTestMulti.TestMulti.Builder emptybuilder = EnumTestMulti.TestMulti.newBuilder();
        // mergeFrom 相当于BeanUtils.copyProperties(dest, orig)
        EnumTestMulti.TestMulti.Builder newBuilder = emptybuilder.mergeFrom(message);
        System.out.println(newBuilder.build());
        System.out.println("======================protobuf转json================================");
        // protobuf转json
        String json = null;
        try {
            json = JsonFormat.printer().print(foo);
            System.out.println(json);
        } catch (Exception e) {
            // TODO
        }
        System.out.println("========================json转protobuf============================");
        // json转protobuf
        NestedMulti.Foo.Builder fooBuilder = NestedMulti.Baz.newBuilder().getBarBuilder().getFooBuilder();
        NestedMulti.Foo msg = null;
        try {
            JsonFormat.parser().merge(json, fooBuilder);
            msg = fooBuilder.build();
            System.out.println(msg);
        } catch (Exception e) {
            // TODO
        }
        System.out.println("========================复制嵌套消息=============================");
        // mergeFrom可以复制嵌套消息
        NestedMulti.Foo.Builder fooBuilderDeep = NestedMulti.Baz.newBuilder().getBarBuilder().getFooBuilder();
        fooBuilderDeep.mergeFrom(msg);
        System.out.println(fooBuilderDeep.build());
    }
}

特别:

当运行环境的protobuf-java依赖和protoc版本不一致时,无法运行protoc生成的java文件。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值