protobuf利用反射来对message类进行设值和获取类里面字段内容,并将message类转为json格式

syntax="proto3";
message simple{
  int32 id=1;
  string name=2;
  repeated string girls=3;
}
//传入类的名字
google::protobuf::Massage*create_message()const char*type_name){
   google::protobuf::Massage*message=NULL;
   //拿到这个类的descriptor
   const google::protobuf::Descriptor* descriptor=
      google::protobuf::DescriptorPool::generated_pool()->FindMesaageTypeByName(type_name);
   if(descriptor){
        //根据descriptor拿到想要的信息
      const google::protobuf::Message* prototype=
            google::protobuf::MessageFactor::generted_factory()->GetPrototype(descriptor);
             if(prototype){
             message=prototype->New();//new这个类
        }
    }
    return message;
}
//利用反射获取message类里面的内容
void traverse_message(google::protobuf::Message* msg){
    if(!msg){
        std::cout<<"msg is NULL"<<std: :endl;
        return;
    }
    //拿到消息类的描述des和反射ref
	const google::protobuf::Descriptor* des=msg->GetDescriptor();
	const google::protobuf::Reflection* ref = msg->GetReflection();
	//通过描述遍历类里面的属性字段
	for (int i=0; i < des->field_count(); i++){
	    //确定字段类型(字段描述fd)
		const google::protobuf::FieldDescriptor* fd = des->field(i);
		//1.可以通过字段描述拿到每个具体字段的**属性名**
		printf("........filed:\t%s\n", fd->name().c_str());
		//3.若字段属性为repeated,即数组类型,则再拿里面的值
	    if (fd->is_repeated()){
	        //遍历数组
			for (int walk = 0; walk < ref->FieldSize(*msg,fd); walk++){
			switch(fd->cpp_type(){
			    //判断数组类型是否INT32
				case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32;
				{
					printf("element: %d\n", ref->GetRepeatedInt32(*msg,fd, walk));
					break;
					}
				case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING;
				{
					printf("element: %s\n"ref->GetRepeatedString(*msg,fd,walk));
					break;
					}
			}	
	     }
	         continue;
       }
       //2.可以通过字段描述拿到每个具体字段的属性名**对应的属性值**
       //遍历cpp类型:int32,int64,double,float,bool,enum,string,message等
       switch (fd->cpp_type()) {
            //获取类型INT32的属性
			case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32;
			{
				printf("value: %d\n", ref->GetInt32(*msg,fd));
				break;
				}
			// 获取类型STRING的属性
			case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING;
			{
				printf("value: %s\n", ref->GetString(*msg,fd).c_str());
				break;
				}
           }
    }

}

int main (){
   GOOGLE_PROTOBUF_VERIFY_VERSION;
   auto msg=create_message("simple");//通过字符串名字创建Message类,反射设计模式
   //给创建的Message类中的属性设置新值
   simple* item_ptr =(simple)*msg;
   const google::protobuf::Descriptor* des=msg->GetDescriptor();
   const google::protobuf::Reflection* ref=msg->GetReflection();
   //在描述里面找到属性名
   cosnt google::protobuf::FieldDescriptor* fd_des=des->FindFieldByName("name");
   //通过反射设置属性值
   if(fd_des){
      ref->SetString(msg,fd_des,"weixiaobao");
    }
   //找到序号为1的属性
   fd_des=des->FindFieldByNumber(1);
   //对序号为1的属性设值
   ref->SetInt32(msg,fd_des,10086);
   //找到第三个属性(repeated) ,可设置多个值
   fd_des=des->FindFieldByName("girls");
   ref->AddString(msg,fd des,"qiuxiang");
   ref->AddString(msg, fd_des,"xiaofang") ;
   ref->AddString(msg,fd_des,"axiang");
   
  traverse_message(item_ptr));
  std::string json=to_json(item_ptr);//将message类反序列化转为json
  cout<<"json:"<<json<<endl;
}

在这里插入图片描述
将message内容转为json:
在这里插入图片描述

//利用反射获取message类里面的内容,将内容反序列化转为json
std::string to_json(google::protobuf::Message* msg){
   std::string json("{")
    if(!msg){
        std::cout<<"msg is NULL"<<std: :endl;
        return std::string("");
    }
    //拿到消息类的描述des和反射ref
	const google::protobuf::Descriptor* des=msg->GetDescriptor();
	const google::protobuf::Reflection* ref = msg->GetReflection();
	
	//通过描述遍历类里面的属性字段
	for (int i=0; i < des->field_count(); i++){
	    //确定字段类型(字段描述fd)
		const google::protobuf::FieldDescriptor* fd = des->field(i);
		//1.可以通过字段描述拿到每个具体字段的**属性名**
		printf("........filed:\t%s\n", fd->name().c_str());
		//3.若字段属性为repeated,即数组类型,则再拿里面的值
	    if (fd->is_repeated()){
	   		json+="\"";
	    	json+=fd->name();
	    	json+="\":[";
	        //遍历数组
			for (int walk = 0; walk < ref->FieldSize(*msg,fd); walk++){
			switch(fd->cpp_type(){
			    //判断数组类型是否INT32
				case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32;
				{
					google::protobuf::int32 item = ref->GetRepeatedInt32(*msg,fd, walk);
					std::string item_str=to_string(item);
					json+=item_str;
					  if(walk!=ref->FieldSize(*msg,fd)){//如果不是最后一个,json还得加一个,
                        json+=",";
                    }
					break;
					}
				case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING;
				{
				    json+="\"";
					json+=ref->GetRepeatedString(*msg,fd,walk).c_str();
				    json+="\"";
				    if(walk!=ref->FieldSize(*msg,fd)){//如果不是最后一个,json还得加一个,
                        json+=",";
                    }
					break;
					}
			}	
	     }
	     json+="]";
	     continue;
       }
       //2.可以通过字段描述拿到每个具体字段的属性名**对应的属性值**
       //遍历cpp类型:int32,int64,double,float,bool,enum,string,message等
       switch (fd->cpp_type()) {
            //获取类型INT32的属性
			case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32;
			{
			    json+="\"";
			    json+=fd->name();
			    json+="\":";
				google::protobuf::int32 item =  ref->GetInt32(*msg,fd));
					std::string item_str=to_string(item);
					json+=item_str;
					  if(i!=des->field_count()-1){//如果不是最后一个,json还得加一个,
                        json+=",";
                    }
				break;
				}
			// 获取类型STRING的属性
			case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING;
			{  
			        json+="\"";
			        json+=fd->name();
			        json+="\":";
				    json+="\"";
					json+=ref->GetString(*msg,fd).c_str();
				    json+="\"";
				    if(i!=des->field_count()-1){//如果不是最后一个,json还得加一个,
                        json+=",";
                    }
				break;
				}
           }
   
    }
        json+="}";
       return json;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将 JSON 格式换为 Protobuf 格式,你可以按照以下步骤进行操作: 1. 定义 Protobuf 协议:首先,你需要使用 Protocol Buffers (Protobuf) 的语法来定义你的消息格式。创建一个 `.proto` 文件,其中包含消息的字段型定义。例如,假设你有一个简单的消息型 `Person`,可以在 `.proto` 文件中定义如下: ```protobuf syntax = "proto3"; message Person { string name = 1; int32 age = 2; } ``` 2. 生成 Protobuf 代码:使用 Protobuf 编译器将 `.proto` 文件生成对应的编程语言代码。例如,如果你使用的是 Python,可以运行以下命令来生成 Python 代码: ``` protoc --python_out=. your_proto_file.proto ``` 这将生成一个名为 `your_proto_file_pb2.py` 的 Python 文件,其中包含用于序列化和反序列化 Protobuf 消息的代码。 3. 解析 JSON 数据:使用你选择的编程语言读取 JSON 数据并将其解析为对象或字典结构。大多数编程语言都提供了 JSON 解析器和序列化器的库。 4. 将数据换为 Protobuf 消息:根据生成的代码,将解析后的数据填充到 Protobuf 消息对象中。例如,在 Python 中,你可以使用生成的 `your_proto_file_pb2` 模块中的来创建和填充消息对象。 5. 序列化为二进制格式:将填充好数据的 Protobuf 消息对象序列化为二进制格式。编程语言的 Protobuf 库通常提供了将消息对象序列化为二进制格式的方法。 下面是一个示例 Python 代码,演示了 JSON Protobuf 的过程: ```python import json import your_proto_file_pb2 # 读取 JSON 数据 json_data = '{"name": "Alice", "age": 25}' data_dict = json.loads(json_data) # 创建 Protobuf 消息对象并填充数据 person = your_proto_file_pb2.Person() person.name = data_dict['name'] person.age = data_dict['age'] # 将 Protobuf 对象序列化为二进制格式 binary_data = person.SerializeToString() # 可以将 binary_data 存储到文件或通过网络进行传输 ``` 这只是一个简单示例,实际的实现可能会根据你的具体需求和编程语言有所不同。请确保根据你使用的编程语言和 Protobuf 版本查阅相应的文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

定位算法工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值