google protobuf 反射的例子

反射就是可以知道一个对象自身的数据属性,例如有哪些字段,字段的值,函数等等。
下面的代码展示了protobuf 对象反射的例子。将一个对象按照反射的字段顺序序列化到string,然后反序列化到对象。最后调用反射打印其字段值,可以看到对象能够还原。

proto文件为(暂时不支持数组):

package tutorial;

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  optional PhoneNumber phone = 4;
  
}

 

#include <string>
#include <map>
#include <iostream>
#include <stdio.h>
#include "person.pb.h"
using namespace tutorial;
using namespace google::protobuf;
using std::cout;
using std::endl;
using std::string;


void serialize_message(const Message& message, std::string* serialized_string) {
    const Descriptor* descriptor = message.GetDescriptor();
    const Reflection* reflection = message.GetReflection();

    for (int i = 0; i < descriptor->field_count(); ++i) {
        const FieldDescriptor* field = descriptor->field(i);
        bool has_field = reflection->HasField(message, field);

        if (has_field) {
            //arrays not supported
            assert(!field->is_repeated());

            switch (field->cpp_type()) {
#define CASE_FIELD_TYPE(cpptype, method, valuetype)\
                case FieldDescriptor::CPPTYPE_##cpptype:{\
                    valuetype value = reflection->Get##method(message, field);\
                    int wsize = field->name().size();\
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));\
                    serialized_string->append(field->name().c_str(), field->name().size());\
                    wsize = sizeof(value);\
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));\
                    serialized_string->append(reinterpret_cast<char*>(&value), sizeof(value));\
                    break;\
                }

                CASE_FIELD_TYPE(INT32, Int32, int);
                CASE_FIELD_TYPE(UINT32, UInt32, uint32_t);
                CASE_FIELD_TYPE(FLOAT, Float, float);
                CASE_FIELD_TYPE(DOUBLE, Double, double);
                CASE_FIELD_TYPE(BOOL, Bool, bool);
                CASE_FIELD_TYPE(INT64, Int64, int64_t);
                CASE_FIELD_TYPE(UINT64, UInt64, uint64_t);
#undef CASE_FIELD_TYPE
                case FieldDescriptor::CPPTYPE_ENUM: {
                    int value = reflection->GetEnum(message, field)->number();
                    int wsize = field->name().size();
                    //写入name占用字节数
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    //写入name
                    serialized_string->append(field->name().c_str(), field->name().size());
                    wsize = sizeof(value);
                    //写入value占用字节数
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    //写入value
                    serialized_string->append(reinterpret_cast<char*>(&value), sizeof(value));
                    break;
                }
                case FieldDescriptor::CPPTYPE_STRING: {
                    std::string value = reflection->GetString(message, field);
                    int wsize = field->name().size();
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    serialized_string->append(field->name().c_str(), field->name().size());
                    wsize = value.size();
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    serialized_string->append(value.c_str(), value.size());
                    break;
                }
                case FieldDescriptor::CPPTYPE_MESSAGE: {
                    std::string value;
                    int wsize = field->name().size();
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    serialized_string->append(field->name().c_str(), field->name().size());
                    const Message& submessage = reflection->GetMessage(message, field);
                    serialize_message(submessage, &value);
                    wsize = value.size();
                    serialized_string->append(reinterpret_cast<char*>(&wsize), sizeof(wsize));
                    serialized_string->append(value.c_str(), value.size());
                    break;
                }
            }
        }
    }
}

void parse_message(const string& serialized_string, Message* message) {
    const Descriptor* descriptor = message->GetDescriptor();
    const Reflection* reflection = message->GetReflection();
    map<string, const FieldDescriptor*> field_map;

    for (int i = 0; i < descriptor->field_count(); ++i) {
        const FieldDescriptor* field = descriptor->field(i);
        field_map[field->name()] = field;
    }

    const FieldDescriptor* field = NULL;
    size_t pos = 0;
    while (pos < serialized_string.size()) {
        int name_size = *(reinterpret_cast<const int*>(serialized_string.substr(pos, sizeof(int)).c_str()));
        pos += sizeof(int);
        string name = serialized_string.substr(pos, name_size);
        pos += name_size;

        int value_size = *(reinterpret_cast<const int*>(serialized_string.substr(pos, sizeof(int)).c_str()));
        pos += sizeof(int);
        string value = serialized_string.substr(pos, value_size);
        pos += value_size;

        map<string, const FieldDescriptor*>::iterator iter =
            field_map.find(name);
        if (iter == field_map.end()) {
            fprintf(stderr, "no field found.\n");
            continue;
        } else {
            field = iter->second;
        }

        assert(!field->is_repeated());
        switch (field->cpp_type()) {
#define CASE_FIELD_TYPE(cpptype, method, valuetype)\
            case FieldDescriptor::CPPTYPE_##cpptype: {\
                reflection->Set##method(\
                        message,\
                        field,\
                        *(reinterpret_cast<const valuetype*>(value.c_str())));\
                cout << field->name() << "\t" << *(reinterpret_cast<const valuetype*>(value.c_str())) << endl;\
                break;\
            }
            CASE_FIELD_TYPE(INT32, Int32, int);
            CASE_FIELD_TYPE(UINT32, UInt32, uint32_t);
            CASE_FIELD_TYPE(FLOAT, Float, float);
            CASE_FIELD_TYPE(DOUBLE, Double, double);
            CASE_FIELD_TYPE(BOOL, Bool, bool);
            CASE_FIELD_TYPE(INT64, Int64, int64_t);
            CASE_FIELD_TYPE(UINT64, UInt64, uint64_t);
#undef CASE_FIELD_TYPE
            case FieldDescriptor::CPPTYPE_ENUM: {
                const EnumValueDescriptor* enum_value_descriptor =
                    field->enum_type()->FindValueByNumber(*(reinterpret_cast<const int*>(value.c_str())));
                reflection->SetEnum(message, field, enum_value_descriptor);
                cout << field->name() << "\t" << *(reinterpret_cast<const int*>(value.c_str())) << endl;
                break;
            }
            case FieldDescriptor::CPPTYPE_STRING: {
                reflection->SetString(message, field, value);
                cout << field->name() << "\t" << value << endl;
                break;
            }
            case FieldDescriptor::CPPTYPE_MESSAGE: {
                Message* submessage = reflection->MutableMessage(message, field);
                parse_message(value, submessage);
                break;
            }
            default: {
                break;
            }
        }
    }
}


void print_field(const Message& message)
{
    const Descriptor* descriptor = message.GetDescriptor();
    const Reflection* reflection = message.GetReflection();

    for (int i = 0; i < descriptor->field_count(); ++i) {
        const FieldDescriptor* field = descriptor->field(i);
        bool has_field = reflection->HasField(message, field);
        assert(!field->is_repeated());
            
        switch (field->cpp_type()) {
#define CASE_FIELD_TYPE(cpptype, method, valuetype)\
            case FieldDescriptor::CPPTYPE_##cpptype:{\
                valuetype value = reflection->Get##method(message, field);\
                if (has_field) {\
                    cout << field->name() << " : " << value << ", type : " << #valuetype << "\n";\
                }  else  {\
                    cout << field->name() << " : " << "None" << ", type : " << #valuetype << "\n";\
                }\
                break;\
            }

            CASE_FIELD_TYPE(INT32, Int32, int);
            CASE_FIELD_TYPE(UINT32, UInt32, uint32_t);
            CASE_FIELD_TYPE(FLOAT, Float, float);
            CASE_FIELD_TYPE(DOUBLE, Double, double);
            CASE_FIELD_TYPE(BOOL, Bool, bool);
            CASE_FIELD_TYPE(INT64, Int64, int64_t);
            CASE_FIELD_TYPE(UINT64, UInt64, uint64_t);
#undef CASE_FIELD_TYPE
            case FieldDescriptor::CPPTYPE_ENUM: {
                int value = reflection->GetEnum(message, field)->number();
                if (has_field)  {
                    cout << field->name() << " : " << value << ", type : " << "enum \n";    
                }
                else  {
                    cout << field->name() << " : " << "None" << ", type : " << "enum \n";
                }
                break;
            }
            case FieldDescriptor::CPPTYPE_STRING: {
                string value = reflection->GetString(message, field);
                if (has_field)  {
                    cout << field->name() << " : " << value << ", type : " << "string \n";  
                }
                else  {
                    cout << field->name() << " : " << "None" << ", type : " << "string \n";
                }
                
                break;
            }
            case FieldDescriptor::CPPTYPE_MESSAGE: {
                const Message& submessage = reflection->GetMessage(message, field);
                print_field(submessage);
                break;
            }
        }
    }
}



int main() 
{
    string str;
	Person person;
	person.set_name("shonm");
	person.set_id(123);
	person.mutable_phone()->set_number("1380000");
	person.mutable_phone()->set_type(Person_PhoneType_WORK);
	serialize_message(person, &str);       //按照自己的方式(反射的字段)序列化

	Person person2;
	parse_message(str, &person2);          //按照自己的方式反序列化
	printf("\n\n");
	print_field(person);                   //根据反射打印字段
	
	printf("\n\n");
	print_field(person2);
}

参考:

 https://izualzhy.cn/protobuf-message-reflection

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值