proto与json互相转换(使用反射)

  • 2019 年 11 月 22 日
  • 笔记

有时,需要动态的根据proto文件来构建一个proto对象。此时,就该反射库上场了。

package jsonpb    import (      "github.com/golang/protobuf/proto"      "github.com/golang/protobuf/ptypes"      "github.com/jhump/protoreflect/desc"      "github.com/jhump/protoreflect/desc/protoparse"      "github.com/jhump/protoreflect/dynamic"      "github.com/rfyiamcool/grpcall"      "google.golang.org/grpc/metadata"      "google.golang.org/grpc/status"      "sync"  )    var globalProtoMap map[string]*desc.FileDescriptor  var IsCached = true  var lk sync.RWMutex    func init() {      globalProtoMap = make(map[string]*desc.FileDescriptor)  }    func getProto(path string) *desc.FileDescriptor {      lk.Lock()      defer lk.Unlock()        if IsCached {          fd, ok := globalProtoMap[path]          if ok {              logging.Debugf("getProto path:%v cached", path)              return fd          }      }      p := protoparse.Parser{      }      fds, err := p.ParseFiles(path)      if err != nil {          logging.Errorf("getProto ParseFiles error:%v", err)          return nil      }      //logging.Debugf("JsonToPb fd %v, err %v", fds[0], err)      fd := fds[0]        if IsCached {          globalProtoMap[path] = fd      }        return fd  }    // JsonToPb 传入proto文件的path, proto中对应的message.name,js的原始数据  // 返回生成的proto.Marshal的[]byte  // example:  // path := "$PROTOPATH/helloworld.proto"  // messageName "helloworld.HelloRequest"  // JsonToPb(path,"helloworld.HelloRequest", []byte(`{"name":"yzh"}`))  func JsonToPb(protoPath, messageName string, jsonStr []byte) ([]byte, error) {      logging.Debugf("JsonToPb protoPath %v", protoPath)        fd := getProto(protoPath)        msg := fd.FindMessage(messageName)        dymsg := dynamic.NewMessage(msg)      err := dymsg.UnmarshalJSON(jsonStr)      if err != nil {          logging.Errorf("JsonToPb UnmarshalJSON error:%v", err)          return nil, nil      }      logging.Debugf("JsonToPb UnmarshalJSON dymsg %v", dymsg)        any, err := ptypes.MarshalAny(dymsg)      if err != nil {          logging.Errorf("JsonToPb MarshalAny error:%v", err)          return nil, nil      }      logging.Debugf("JsonToPb marshal any %v", any.Value)      return any.Value, nil  }    // PbToJson 传入proto的byte数据,返回它对应的json数据  // example:  // path := "$PROTOPATH/helloworld.proto"  // messageName "helloworld.HelloRequest"  // jsonByte, err := PbToJson(path, messageName, pbByte)  func PbToJson(protoPath, messageName string, protoData []byte) ([]byte, error) {      logging.Debugf("PbToJson protoPath %v", protoPath)      fd := getProto(protoPath)      msg := fd.FindMessage(messageName)      dymsg := dynamic.NewMessage(msg)        err := proto.Unmarshal(protoData, dymsg)      logging.Debugf("PbToJson Unmarshal err:%v", err)        jsonByte, err := dymsg.MarshalJSON()      return jsonByte, err  }