Golang中protobuf版本升级

本文主要涉及从老版本"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{}

发表评论

邮箱地址不会被公开。 必填项已用*标注