将任意的protobuf对象转换为json格式的字符串

#include "json/json.h"
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include "pro1.pb.h" 
#include "pro2.pb.h" 
#include <fstream>
#include <iostream>
#include <cstdio>
using namespace ::google::protobuf;
using namespace std;
using namespace Json;
using namespace pro1;
using namespace pro2;
typedef long long                           ll;
string outputname[10]={"ans1.json","ans2.json"};
//对protobuf 反射机制的应用是实现程序的关键
typedef ::google::protobuf::Message         ProtobufMsg;            //消息类型
typedef ::google::protobuf::Reflection      ProtobufReflection;     //反射
typedef ::google::protobuf::FieldDescriptor ProtobufFieldDescriptor;//字段的描述
typedef ::google::protobuf::Descriptor      ProtobufDescriptor;      //对象的描述
void RepeatedMessage2Json(const ProtobufMsg& message, const ProtobufFieldDescriptor* field,const ProtobufReflection* reflection, Json::Value& json, bool enum2str) ;


//pb对象 js对象 是否转换enum
void PbMsg2Json(const ProtobufMsg& src, Json::Value& dst, bool enum2str =false) 
{

    // 拿到对象的描述包. --形式
    const ProtobufDescriptor* descriptor = src.GetDescriptor();
    //获取失败的报错
    if (descriptor == NULL )
    {
        cout <<"描述包获取失败"<<endl;
        return;
    }

    // 拿到对象的反射配置. --实际值
    //对pb对象的自动读写主要通过该类完成
    const ProtobufReflection* reflection = src.GetReflection();
    if(reflection == NULL)
    {
        cout <<"反射配置获取失败"<<endl;
        return;
    }
    

    //得到当前对象的数据字段个数
    int count = descriptor->field_count();

    //以下针对每个字段进行相应的操作
    for (int i = 0; i < count; ++i) 
    {
        //拿到对象第i个字段的描述
        const ProtobufFieldDescriptor* field = descriptor->field(i);

        if(field==NULL)
        {
            cout<<"对象第i个字段的描述获取失败"<<endl;
            return ;
        }
        
        //若当前字段是数组 确实有重复的值
        if (field->is_repeated()) 
        {
            if (reflection->FieldSize(src, field) > 0)//若当前字段实际存在赋值进入处理repeated操作
                RepeatedMessage2Json(src, field, reflection, dst[field->name()], enum2str);//field->name()
            continue;
        }
 
        //若当前字段虽然是数组 但实际上没有被赋值
        if (!reflection->HasField(src, field)) 
        {
            continue;
        }
    

        //对不同的字段类型
        switch (field->type()) 
        {
            //嵌套一个message 
            case ProtobufFieldDescriptor::TYPE_MESSAGE: 
            {
                const ProtobufMsg& tmp_message = reflection->GetMessage(src, field);
                if ( tmp_message.ByteSize()) PbMsg2Json(tmp_message, dst[field->name()],enum2str);//操作field->name()字段
                break;
            } 

            //bool
            case ProtobufFieldDescriptor::TYPE_BOOL:
                dst[field->name()] = reflection->GetBool(src, field) ? true : false;
                break;

            
            //ENUM
            case ProtobufFieldDescriptor::TYPE_ENUM: 
            {
                const ::google::protobuf::EnumValueDescriptor* enum_value_desc = reflection->GetEnum(src, field);
                if (enum2str) //是否需要将enum数据转换成相应字符串
                {
                    dst[field->name()] = enum_value_desc->name();
                } 
                else 
                {
                    dst[field->name()] = enum_value_desc->number();
                }
                break;
            } 
 
            case ProtobufFieldDescriptor::TYPE_INT32:
            case ProtobufFieldDescriptor::TYPE_SINT32:
            case ProtobufFieldDescriptor::TYPE_SFIXED32:
                dst[field->name()] = Json::Int(reflection->GetInt32(src, field));
                break;
 
            case ProtobufFieldDescriptor::TYPE_UINT32:
            case ProtobufFieldDescriptor::TYPE_FIXED32:
                dst[field->name()] = Json::UInt(reflection->GetUInt32(src, field));
                break;
 
            case ProtobufFieldDescriptor::TYPE_INT64:
            case ProtobufFieldDescriptor::TYPE_SINT64:
            case ProtobufFieldDescriptor::TYPE_SFIXED64:
                dst[field->name()] = Json::Int64(reflection->GetInt64(src, field));
                break;
 
            case ProtobufFieldDescriptor::TYPE_UINT64:
            case ProtobufFieldDescriptor::TYPE_FIXED64:
                dst[field->name()] = Json::UInt64(reflection->GetUInt64(src, field));
                break;
 
            case ProtobufFieldDescriptor::TYPE_FLOAT:
                dst[field->name()] = reflection->GetFloat(src, field);
                break;
            
            case ProtobufFieldDescriptor::TYPE_DOUBLE:
                dst[field->name()] = reflection->GetDouble(src, field);
                break;

            case ProtobufFieldDescriptor::TYPE_STRING:
            case ProtobufFieldDescriptor::TYPE_BYTES:
                dst[field->name()] = reflection->GetString(src, field);
                break;
 
            default:
                break;
        }
    }
}

//pb 字段 反射实值 json对象
void RepeatedMessage2Json(const ProtobufMsg& message,const ProtobufFieldDescriptor* field,const ProtobufReflection* reflection, Json::Value& json, bool enum2str) 
{
    if (NULL == field ) 
    {
        cout<<"字段传入失败"<<endl;
        return ;
        //PbMsg2Json(message, json, enum2str);
    }
    

    //对字段中的重复数据进行判断
    for (int i = 0; i < reflection->FieldSize(message, field); ++i) 
    {
        Json::Value tmp_json;
        switch (field->type()) 
        {

            //若重复mes
            case ProtobufFieldDescriptor::TYPE_MESSAGE: 
            {
                //获得mes数组字段中第i个mes
                const ProtobufMsg& tmp_message = reflection->GetRepeatedMessage(message, field, i);

                //只要该mes存在字节则进行转换
                if ( tmp_message.ByteSize()) 
                {
                    PbMsg2Json(tmp_message, tmp_json , enum2str);
                }

                break;
            } 
 
            case ProtobufFieldDescriptor::TYPE_BOOL:
                tmp_json[field->name()] = reflection->GetRepeatedBool(message, field, i) ? true : false;
                break;
 
            case ProtobufFieldDescriptor::TYPE_ENUM: 
            {
                const ::google::protobuf::EnumValueDescriptor* enum_value_desc = reflection->GetRepeatedEnum(message, field, i);
                if (enum2str) 
                {
                    tmp_json = enum_value_desc->name();
                } 
                else 
                {
                    tmp_json = enum_value_desc->number();
                }
                break;
            } 
 
            case ProtobufFieldDescriptor::TYPE_INT32:
            case ProtobufFieldDescriptor::TYPE_SINT32:
            case ProtobufFieldDescriptor::TYPE_SFIXED32:
                tmp_json[field->name()] = reflection->GetRepeatedInt32(message, field, i);
                break;
 
            case ProtobufFieldDescriptor::TYPE_UINT32:
            case ProtobufFieldDescriptor::TYPE_FIXED32:
                tmp_json[field->name()] = reflection->GetRepeatedUInt32(message, field, i);
                break;
 
            case ProtobufFieldDescriptor::TYPE_INT64:
            case ProtobufFieldDescriptor::TYPE_SINT64:
            case ProtobufFieldDescriptor::TYPE_SFIXED64:
                tmp_json[field->name()] = (Json::Int64)reflection->GetRepeatedInt64(message, field, i);
                break;
 
            case ProtobufFieldDescriptor::TYPE_UINT64:
            case ProtobufFieldDescriptor::TYPE_FIXED64:
                tmp_json[field->name()] = Json::UInt64(reflection->GetRepeatedUInt64(message, field, i));
                break;
 
            case ProtobufFieldDescriptor::TYPE_FLOAT:
                tmp_json[field->name()] = reflection->GetRepeatedFloat(message, field, i);
                break;
 
            case ProtobufFieldDescriptor::TYPE_STRING:
            case ProtobufFieldDescriptor::TYPE_BYTES:
                tmp_json[field->name()] = reflection->GetRepeatedString(message, field, i);
                break;
 
            default:
                break;
        }
        //对这个数组进行
        json.append(tmp_json);
    }
}



void init1(pro1:: Person &person)
{
    cout<<"<//设置protobuf1初始值中...\n"<<endl;
    person.set_name("Zed222");
    person.set_id(222);
    person.set_email("1208086@qq.com");
    
    pro1::Person::PhoneNumber *phone1 = person.add_phones();// add_phones 返回指针类型
    phone1->set_number("17569150186"); 
    phone1->set_type(pro1::Person::MOBILE);

    pro1::Person::PhoneNumber *phone2 = person.add_phones();
    phone2->set_number("110");
    phone2->set_type(pro1::Person::HOME);
}

void init2(pro2:: City &city)
{
    cout<<"<//设置protobuf2初始值中...\n"<<endl;
    city.set_nowname("Beijing");
    city.set_id(110000);
    city.set_gdp(41610.9);
    city.set_country("Chinese");
    city.add_usedname("Peking");
    city.add_usedname("燕京");
    city.add_usedname("幽州");
    
}
void output(Json::Value &root,int num)
{
    
    if(num==1)
    {
        ofstream ofs(outputname[num-1]);
        if(!ofs.is_open())
        {
            printf("打开%s失败\n",&outputname[num-1]);
            exit(1);
        }
        ofs<<root<<endl;
        ofs.close();
    }
    else if(num==2)
    {
        ofstream ofs(outputname[num-1]);
        if(!ofs.is_open())
        {
            printf("打开%s失败\n",&outputname[num-1]);
            exit(1);
        }
        ofs<<root<<endl;
        ofs.close();
        
    }
    printf("输出到%d完毕\n",num);
   
}

void work(int num)
{
    Json::Value root;
    pro1::Person person;
    pro2::City city;
    if(num==1)
    {
        init1(person);
        PbMsg2Json(person,root,true);
    }
    else 
    {
        init2(city);
        PbMsg2Json(city,root,true);
    }
    printf("数据%d转换中...\n",num);
    output(root,num);
}

int main()
{

    work(1);
    work(2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ProtobufProtocol Buffers)是一种轻量级的数据序列化格式,用于结构化数据的存储和交换。它可以将数据对象序列化为二进制格式,也可以将二进制数据反序列化为数据对象。相比于JSONProtobuf具有更高的性能和更小的数据体积。 在使用Protobuf进行DTO(Data Transfer Object)对象JSON之间的相互转换时,可以按照以下步骤进行: 1. 定义Protobuf消息型:首先需要定义Protobuf消息型,即定义数据结构和字段。可以使用Protobuf的语言特定的语法来定义消息型,例如使用.proto文件定义。 2. 生成代码:根据定义的Protobuf消息型,使用Protobuf编译器生成对应的代码文件。不同的编程语言可能有不同的编译器,例如对于Java语言可以使用protoc编译器生成Java。 3. 将DTO对象转换Protobuf消息:使用生成的代码,将DTO对象转换为对应的Protobuf消息对象。可以通过设置消息对象的字段值来实现。 4. 将Protobuf消息转换JSON:使用Protobuf提供的序列化方法,将Protobuf消息对象序列化为二进制数据。然后可以使用JSON库将二进制数据转换JSON格式字符串。 5. 将JSON转换Protobuf消息:使用JSON库将JSON格式字符串解析为二进制数据。然后使用Protobuf提供的反序列化方法,将二进制数据反序列化为Protobuf消息对象。 总结一下,将DTO对象转换JSON可以分为两步:DTO对象转换Protobuf消息,Protobuf消息转换JSON。反之,将JSON转换为DTO对象也可以分为两步:JSON转换Protobuf消息,Protobuf消息转换为DTO对象

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值