反射就是可以知道一个对象自身的数据属性,例如有哪些字段,字段的值,函数等等。
下面的代码展示了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);
}
参考: