Protobuf动态解析在Java中的应用 包含例子程序

最近在做ProtoBuf相关的项目,其中用到了动态解析,网上看了下相关资料和博文都比较少,自己来写一个记录一下学习过程。

Protocol Buffers是结构化数据格式标准,提供序列化和反序列方法,用于存储和交换。语言中立,平台无关、可扩展。目前官方提供了C++、JavaPython API,也有其他语言的开源api(比如php)。可通过 .proto文件生成对应语言的类代码

如果已知protobuf内容对应的是哪个类对象,则可以直接使用反序列化方法搞定(Xxx.parseFrom(inputStream)由二进制转换,TextFormat.merge(string, xxxBuilder)由文本转换)

而我们经常遇到的情况是,拿到一个被protobuf序列化的二进制内容,但不知道它的类型,无法获得对应的类对象。这种多见于需要处理各种各样未知的ProtoBuf对象的系统。ProtoBuf提供了动态解析机制来解决这个问题,它要求提供二进制内容的基础上,再提供对应类的Descriptor对象,在解析时通过DynamicMessage类的成员方法来获得对象结果。

最后问题就是Descriptor对象从哪里来?这是通过protoc --descriptor_set_out=$outputpath 命令生成descriptor文件,进而得到的。代码如下:

option java_package="com.liulei.cinema";

enum MovieType{
    CHILDREN=1;
    ADULT=2;
    NORMAL=3;
    OHTER=4;
}

enum Gender{
    MAN=1;
    WOMAN=2;
    OTHER=3;
}

message Movie{
    required string name=1;
    required MovieType type=2;
    optional int32 releaseTimeStamp=3;
    optional string description=4;
}

message Customer{
    required string name=1;
    optional Gender gender=2;
    optional int32 birthdayTimeStamp=3;
}

message Ticket{
    required int32 id=1;
    required Movie movie=2;
    required Customer customer=3;
}

cinema.proto

-------------------------------------------------

public static void main( String[] args ) {

Cinema.Movie.Builder movieBuilder = Cinema.Movie.newBuilder();
        movieBuilder.setName("The Shining");
        movieBuilder.setType(Cinema.MovieType.ADULT);
        movieBuilder.setReleaseTimeStamp(327859200);

System.out.println("Dynamic Message Parse by proto file");
        try {
            byte[] buffer3 = new byte[movieBuilder.build().getSerializedSize()];
            CodedOutputStream codedOutputStream3 = CodedOutputStream.newInstance(buffer3);
            try {
                movieBuilder.build().writeTo(codedOutputStream3);
                System.out.println(buffer3);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String protocCMD = "protoc --descriptor_set_out=cinema.description ./cinema.proto --proto_path=.";
            Process process = Runtime.getRuntime().exec(protocCMD);
            process.waitFor();
            int exitValue = process.exitValue();
            if (exitValue != 0) {
                System.out.println("protoc execute failed");
                return;
            }
            Descriptors.Descriptor pbDescritpor = null;
            DescriptorProtos.FileDescriptorSet descriptorSet = DescriptorProtos.FileDescriptorSet.parseFrom(new FileInputStream("./cinema.description"));
            for (DescriptorProtos.FileDescriptorProto fdp : descriptorSet.getFileList()) {
                Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom(fdp, new Descriptors.FileDescriptor[]{});
                for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) {
                    if (descriptor.getName().equals("Movie")) {
                        System.out.println("Movie descriptor found");
                        pbDescritpor = descriptor;
                        break;
                    }
                }
            }
            if (pbDescritpor == null) {
                System.out.println("No matched descriptor");
                return;
            }
            DynamicMessage.Builder pbBuilder = DynamicMessage.newBuilder(pbDescritpor);

Message pbMessage = pbBuilder.mergeFrom(buffer3).build();
            System.out.println(pbMessage);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f3d9b992c59c571ba54c2fd4ddffbb81.html