本文主要涉及从老版本"github.com/golang/protobuf" 迁移为新版本 "google.golang.org/protobuf" 所要注意到的技术细节;其中还有少量新版本使用方法;
1. 获取google代码protobuf
# 配置go 代理
go env -w GOPROXY="https://goproxy.cn,direct"
# 下载protobuf代码到${GOPATH}/pkg/google.golang.org/protobuf
go get google.golang.org/protobuf
# 下载protobuf指定版本
go get google.golang.org/protobuf@v1.27.1
git clone https://ghproxy.com/https://google.golang.org/protobuf
2. 根据名称获取pb并创建结构体
//"github.com/golang/protobuf/jsonpb" //老版本
//"github.com/golang/protobuf/proto" //老版本
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
// ProtoWithName is used to marshall proto message data alongside the proto
// message name.
type ProtoWithName struct {
ProtoMsgName string
ProtoMsgData string
}
// proto.MarshalTextString(item) 老版本 "github.com/golang/protobuf/proto"
// prototext.Marshal(item) 新版本 "google.golang.org/protobuf/encoding/prototext"
// MarshalJSON marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) MarshalJSON() ([]byte, error) {
var (
msgName string
msgData string
err error
)
if p != nil {
msgName = string(proto.MessageName(p.Message))
msgbin, err := proto.Marshal(p.Message)
if err != nil {
return nil, err
}
msgData = string(msgbin)
}
pwn, err := json.Marshal(ProtoWithName{
ProtoMsgName: msgName,
ProtoMsgData: msgData,
})
if err != nil {
return nil, err
}
return pwn, nil
}
// UnmarshalJSON un-marshalls proto message using the marshaller from jsonpb.
// The jsonpb package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffers.
func (p *RecordedProtoMessage) UnmarshalJSON(data []byte) error {
var pwn ProtoWithName
if err := json.Unmarshal(data, &pwn); err != nil {
return err
}
p.ProtoMsgName = pwn.ProtoMsgName
if p.ProtoMsgName == "" {
return nil
}
//msgType := proto.MessageType(pwn.ProtoMsgName) //老版本
// 获取full name对应的message ,如果不存在则返回error
msgType, err1 := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(pwn.ProtoMsgName))
if err1 != nil {
return err1
}
if msgType == nil {
return fmt.Errorf("unknown proto message: %s", p.ProtoMsgName)
}
//msg := reflect.New(msgType.Elem()).Interface().(proto.Message) //老版本
msg := msgType.New().Interface()
var err error
if len(pwn.ProtoMsgData) > 0 && pwn.ProtoMsgData[0] == '{' {
//err = jsonpb.UnmarshalString(pwn.ProtoMsgData, msg) //老版本
err = proto.Unmarshal([]byte(pwn.ProtoMsgData), msg) //protojson
} else {
//err = proto.UnmarshalText(pwn.ProtoMsgData, msg) //老版本
err = prototext.Unmarshal([]byte(pwn.ProtoMsgData), msg)
}
if err != nil {
return err
}
p.Message = msg
return nil
}
3. AnyPb 转换 proto.Message
3.1. Marshal Any
// 老版本
// types "github.com/golang/protobuf/ptypes"
// any, err := types.MarshalAny(pb)
// 新版本
// "google.golang.org/protobuf/types/known/anypb"
any, err := anypb.New(pb)
if err != nil {
return nil, err
}
3.2. Unmarshal Any
// 老版本
// types "github.com/golang/protobuf/ptypes"
// var any types.DynamicAny
// if err := types.UnmarshalAny(item.GetData().GetAny(), &any); err != nil {
// return nil, err
// }
// 新版本
// "google.golang.org/protobuf/types/known/anypb"
if dst,err :=anypb.UnmarshalNew(item.GetData().GetAny(),nil);err != nil {
return nil, err
}
3.3. 空proto.Message赋值
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/protobuf/proto"
var Value proto.Message = &empty.Empty{}