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 }