google protocol buffer全解析------田纪原,快速上手

 }
unknownFields.writeTo(output);

}


对于Person类,我们最后再看一下parseFrom方法,这个方法有很多的重载,然而本质都是一样的,通过***PARSER\***去处理数据,这里我就不全贴出来了

```java
public static cn.tera.protobuf.model.BasicUsage.Person parseFrom(byte[] data)
        throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
}

查看PARSER对象,这里正是会调用Person的接受Stream参数的构造函数,和前文对应

private static final com.google.protobuf.Parser<Person>
        PARSER = new com.google.protobuf.AbstractParser<Person>() {
   
    @java.lang.Override
    public Person parsePartialFrom(
            com.google.protobuf.CodedInputStream input,
            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
            throws com.google.protobuf.InvalidProtocolBufferException {
   
        return new Person(input, extensionRegistry);
    }
};

4).Builder类

Builder类为Person的内部类,一样实现了PersonOrBuilder接口,不过额外定义了set的方法

public static final class Builder extends
        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
        // @@protoc_insertion_point(builder_implements:Person)
        cn.tera.protobuf.model.BasicUsage.PersonOrBuilder {
   
    ...
}

这里的get方法的逻辑和Person类一样,不过特别注意的是,这里的name_和Person的getName方法中的name_不是同一个对象,而是分别属于Builder类和Person类的private字段

public java.lang.String getName() {
   
    java.lang.Object ref = name_;
    if (!(ref instanceof java.lang.String)) {
   
        com.google.protobuf.ByteString bs =
                (com.google.protobuf.ByteString) ref;
        java.lang.String s = bs.toStringUtf8();
        name_ = s;
        return s;
    } else {
   
        return (java.lang.String) ref;
    }
}

查看set方法,比较简单,就是一个直接的赋值操作

public Builder setName(
        java.lang.String value) {
   
    if (value == null) {
   
        throw new NullPointerException();
    }

    name_ = value;
    onChanged();
    return this;
}

最后,我们来看下Builder的build方法,这里调用了buildPartial方法

@java.lang.Override
public cn.tera.protobuf.model.BasicUsage.Person build() {
   
    cn.tera.protobuf.model.BasicUsage.Person result = buildPartial();
    if (!result.isInitialized()) {
   
        throw newUninitializedMessageException(result);
    }
    return result;
}

查看buildPartial方法,可以看到这里调用了Person获取builder参数的构造函数,和前文对应

构造完成后,将Builder中的各种字段赋值给Person中的相应字段,即完成了构造

@java.lang.Override
public cn.tera.protobuf.model.BasicUsage.Person buildPartial() {
   
    cn.tera.protobuf.model.BasicUsage.Person result = new cn.tera.protobuf.model.BasicUsage.Person(this);
    result.name_ = name_;
    result.id_ = id_;
    result.email_ = email_;
    onBuilt();
    return result;
}

总结一下:

1.protocol buffer需要定义.proto描述文件,然后通过google提供的编译器生成特定的模型文件,之后就可以作为正常的java对象使用了

2.不可以直接创建对象,需要通过Builder进行

3.只有Builder才可以进行set

4.可以通过对象的toByteArray()和parseFrom()方法进行编码和解码

5.模型文件很大(至少在java这里是如此),其中所有的代码都是定制的,这其实是它很大的缺点之一

接着我们将继续深入探究protobuf的编码原理。

主要分为两个部分

第一部分是之前留下的几个伏笔展示protobuf的使用特性

第二部分是分析protobuf的编码原理,解释特性背后的原因

第一部分,Protobuf使用特性

1.不同类型对象的转换

我们先定义如下一个.proto文件

syntax = "proto3";

option java_package = "cn.tera.protobuf.model";
option java_outer_classname = "DifferentModels";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

message Article {
  string title = 1;
  int32 wordsCount = 2;
  string author = 3;
}

其中我们定义了2个模型,一个Person,一个Article,虽然他们的字段名字不相同,但是类型和编号都是一致的

接着我们生成.java文件,最终文件结构如下图

img

此时我们尝试做如下的一个转换

/**
 * 测试不同模型间的转换
 * @throws Exception
 */
@Test
public void parseDifferentModelsTest() throws Exception {
   
    //创建一个Person对象
    DifferentModels.Person person = DifferentModels.Person.newBuilder()
            
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值