protobuf 自定义extend

1、proto2  extension

proto2 extensions 官网指导说明:

https://developers.google.com/protocol-buffers/docs/proto#extensions

定义:

https://github.com/golang/protobuf/blob/4846b58453b3708320bdb524f25cc5a1d9cda4d4/internal/testprotos/proto2_proto/test.proto#L266

使用方法:

https://github.com/golang/protobuf/blob/master/proto/extensions_test.go

本文重点说明proto3,但proto3也是在proto2的基础上展开的,在理解以上链接内容可以继续向下阅读。

2、proto3 option

proto3 不支持extension,只支持option, option传值设置:

https://developers.google.com/protocol-buffers/docs/proto3#options

 

具体option可以分为:

FileOptions

MessageOptions

FieldOptions

OneofOptions

EnumOptions

EnumValueOptions

ServiceOptions

MethodOptions

UninterpretedOption

 

其字段定义见:

https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto

官网也有对应使用测试:

https://github.com/protocolbuffers/protobuf/blob/master/csharp/protos/unittest_custom_options_proto3.proto

3、go代码 处理proto3 option值

test.proto:

syntax = "proto3";


import "google/protobuf/descriptor.proto";
import "google/protobuf/any.proto";


extend google.protobuf.FileOptions {
    uint64 file_opt1 = 1000;
}
message mymessage{
    int32 x = 10;
}
extend google.protobuf.MessageOptions {
    mymessage mymsg = 1000 ;
}
extend google.protobuf.FieldOptions {
  string field_opt1 = 1000;
  string field_opt2 = 1001;
  mymessage field_opt3 = 1002;
}
extend google.protobuf.OneofOptions {
  int32 oneof_opt1 = 1000;
}
extend google.protobuf.EnumOptions {
  int32 enum_opt1 = 1000;
}
extend google.protobuf.EnumValueOptions {
  int32 enum_value_opt1 = 1000;
}
extend google.protobuf.ServiceOptions {
  sint64 service_opt1 = 1000;
}


option (file_opt1) = 1;


message usemymessage{
    option(mymsg) = {x:1} ;
    string field1 = 1 [(field_opt1)="field1", (field_opt2)="field1"];
    string field2 = 2 [(field_opt3) = {
            x: 100;
        }];
    oneof AnOneof{
        option (oneof_opt1) = 100;
        int32 oneofint = 3;
        string oneofstring = 4;
    }
    enum AnEnum {
        option (enum_opt1) = 100;
        ANENUM_UNSPECIFIED = 0;
        ANENUM_VAL1 = 1;
        ANENUM_VAL2 = 2 [(enum_value_opt1) = 100];
    }
    int32 test = 20;
    repeated google.protobuf.Any details = 21;
}
message usemymessagenonoption{
    string field1 = 1;
    string field2 = 2;
    oneof AnOneof{
        int32 oneofint = 3;
        string oneofstring = 4;
    }
    enum AnEnum {
        ANENUM_UNSPECIFIED = 0;
        ANENUM_VAL1 = 1;
        ANENUM_VAL2 = 2;
    }
    int32 test = 20;
    repeated google.protobuf.Any details = 21;
}

为了方便测试,下载了https://github.com/golang/protobuf,到proto文件家下新建test文件

把test.proto放入test文件夹内,编译命令 protoc --go_out=.  *.proto 生成test.pb.go文件

 

编译中发现:

  • FieldOptions字段不可省略括号
string field1 = 1 [(field_opt1)="field1", (field_opt2)="field1"];  //field_opt1必须加括号
  • proto3不能显示设置option default 值
extend google.protobuf.FileOptions {    
uint64 file_opt1 = 1000 [default = 100];
}  

   这样编译时会报Explicit default values are not allowed in proto3错,[default = 100]要删除

然后到proto/extensions_test.go 文件中加入以下测试代码:

func TestProtoOption(t *testing.T) {
    usm := &test.Usemymessage{
        Field1: "usm",
        Field2: "usm",
    }
    usmnonopt := &test.Usemymessagenonoption{
        Field1: "usm",
        Field2: "usm",
    }
    usmf, usmd := descriptor.ForMessage(usm)
    _, usmnonoptd := descriptor.ForMessage(usmnonopt)

    //FileOptions
    if v, err := proto.GetExtension(usmf.Options, test.E_FileOpt1); err == nil {
        t.Logf("GetExtensions(usmf.Options, test.E_FileOpt1) file_opt1:%d", *(v.(*uint64)))
    } else {
        t.Fatalf("GetExtensions(usmf.Options, test.E_FileOpt1) failed: %v", err)
    }
    /*output:
      GetExtensions(usmf.Options, test.E_FileOpt1) file_opt1:1
    */


    //MessageOptions
    if _, err := proto.GetExtension(usmnonoptd.Options, test.E_Mymsg); err == nil {
        t.Fatalf("GetExtension(usmd.Options, test.E_Mymsg) succ")
    } else {
        if err := proto.SetExtension(usmnonoptd.Options, test.E_Mymsg, &test.Mymessage{X: 100}); err != nil {
            t.Logf("Usemymessagenonoption can't SetExtension and GetExtension")
        }
    }

    if v, err := proto.GetExtension(usmd.Options, test.E_Mymsg); err == nil {
        t.Logf("GetExtension(usmd.Options, test.E_Mymsg) mymsg default:%v", *(v.(*test.Mymessage)))
        setmymsg := &test.Mymessage{X: 100}
        if err := proto.SetExtension(usmd.Options, test.E_Mymsg, setmymsg); err == nil {
            if v1, err1 := proto.GetExtension(usmd.Options, test.E_Mymsg); err1 == nil {
                t.Logf("GetExtension(usmd.Options, test.E_Mymsg) mymsg  after SetExtension:%v", *(v1.(*test.Mymessage)))
            }
        }
    } else {
        t.Fatalf("GetExtension(usmd.Options, test.E_Mymsg) failed: %v", err)
    }
    /*output:
      Usemymessagenonoption can't SetExtension and GetExtension
      GetExtension(usmd.Options, test.E_Mymsg) mymsg default:{1 {} [] 0}
      GetExtension(usmd.Options, test.E_Mymsg) mymsg  after SetExtension:{100 {} [] 0}
    */

    //FieldOptions
    for _, field := range usmd.Field {
        if *(field.Name) == "field1" {
            if v, err := proto.GetExtensions(field.Options, []*proto.ExtensionDesc{test.E_FieldOpt1, test.E_FieldOpt2}); err == nil {
                t.Logf("field1 field_opt1 default:%v, field1 field_opt1 default:%v", *(v[0].(*string)), *(v[1].(*string)))
            } else {
                t.Fatalf("GetExtension(usmd.Options, []*proto.ExtensionDesc{test.E_FieldOpt1, test.E_FieldOpt2}) failed: %v", err)
            }
        }
        if *(field.Name) == "field2" {
            if v, err := proto.GetExtension(field.Options, test.E_FieldOpt3); err == nil {
                t.Logf("field2 field_opt3 default:%v", *(v.(*test.Mymessage)))
            } else {
                t.Fatalf("GetExtensions(field.Options, test.E_FieldOpt3) failed: %v", err)
            }
        }
    }
    /*output:
      field1 field_opt1 default:field1, field1 field_opt1 default:field1
      field2 field_opt3 default:{100 {} [] 0}
    */

}

 

你可能感兴趣的:(go,protobuf,go,golang)