google protobuf 反射的例子
阿新 • • 發佈:2019-02-01
反射就是可以知道一個物件自身的資料屬性,例如有哪些欄位,欄位的值,函式等等。
下面的程式碼展示了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); }
參考: