proto与json互相转换(使用反射) 有时,需要动态的根据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 } ``` ## 使用jsonpb库进行转换 还有一个库,叫jsonpb,可以在已知proto的情况下很快的将其转换为一个json ``` "google.golang.org/protobuf/encoding/protojson" func pb2JSON(pb proto.Message) string { ma := protojson.MarshalOptions{EmitUnpopulated: true} jsonBytes, _ := ma.Marshal(pb) return string(jsonBytes) } ``` 有时,需要用这个老版本的(proto库是github上那个) ``` import "github.com/golang/protobuf/jsonpb" import "github.com/golang/protobuf/proto" func pb2JSON(pb proto.Message) string { ma := jsonpb.Marshaler{} js, _ := ma.MarshalToString(pb) return string(js) } ``` 来自 大脸猫 写于 2019-06-04 19:12 -- 更新于2022-06-15 16:38 -- 1 条评论