前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >proto与json互相转换(使用反射)

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

作者头像
超级大猪
发布2019-11-22 00:13:54
7.1K0
发布2019-11-22 00:13:54
举报

有时,需要动态的根据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
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档