Google Protocol Buffers에서 Reflection 사용법 Programming

Protocol Buffers(이하 PB)에 대한 설명은 이전 포스트를 참고해주세요.
http://javawork.egloos.com/2720889

PB에서 Reflection을 사용하면 정의된 필드/값에 하나씩 접근할수 있습니다. 이런 방식으로 PB의 소스를 수정하지 않고 여러 기능을 추가할수 있습니다. 예를 들면 제가 하려고 하는, 직렬화된 PB 버퍼를 JSON 형식으로 변환하기, 같은 기능이죠.

아래 코드는 PB에서 제공하는 text format과 같은 형식의 문자열을 출력하는 예제입니다. .proto 파일은 이전 포스트에서 사용한 데이터를 그대로 사용했습니다.

#include <fstream>
#include <string>
#include "addressbook.pb.h"
#include <google/protobuf/descriptor.h>

using namespace std;
using namespace google;

void PrintGroupField(const protobuf::Message& message, const protobuf::FieldDescriptor* descriptor);
void PrintField(const protobuf::Message& message, const protobuf::FieldDescriptor* descriptor);
void IteratingWithDescriptor(const protobuf::Message& root_message);

void PrintGroupField(const protobuf::Message& message, const protobuf::FieldDescriptor* descriptor)
{
const protobuf::Reflection* reflection = message.GetReflection();
int repeated_fieldCount = reflection->FieldSize(message, descriptor);
const protobuf::Descriptor* child_descriptor = descriptor->message_type();
for(int j=0;j<repeated_fieldCount;++j)
{
printf("%s {\n", descriptor->name().c_str());
const protobuf::Message& child_message = reflection->GetRepeatedMessage(message, descriptor, j);
const protobuf::Reflection* child_reflection = child_message.GetReflection();
int child_fieldCount = child_descriptor->field_count();
for(int k=0;k<child_fieldCount;++k)
{
const protobuf::FieldDescriptor* curChildFd = child_descriptor->field(k);
printf(" ");
PrintField(child_message, curChildFd);
}
printf("}\n");
}
}

void PrintField(const protobuf::Message& message, const protobuf::FieldDescriptor* descriptor)
{
const protobuf::Reflection* reflection = message.GetReflection();
switch(descriptor->type())
{
case protobuf::FieldDescriptor::TYPE_INT32:
{
printf("%s : %d", descriptor->name().c_str(), reflection->GetInt32(message, descriptor));
break;
}
case protobuf::FieldDescriptor::TYPE_STRING:
{
printf("%s : %s", descriptor->name().c_str(), reflection->GetString(message, descriptor).c_str());
break;
}
case protobuf::FieldDescriptor::TYPE_ENUM:
{
const protobuf::EnumValueDescriptor* enumValue = reflection->GetEnum(message, descriptor);
printf("%s : %s", descriptor->name().c_str(), enumValue->name().c_str());
break;
}
case protobuf::FieldDescriptor::TYPE_MESSAGE:
{
PrintGroupField(message, descriptor);
break;
}
}
printf("\n");
}

void IteratingWithDescriptor(const protobuf::Message& root_message)
{
const protobuf::Descriptor* root_descriptor = root_message.GetDescriptor();
int root_fieldCount = root_descriptor->field_count();
for(int i=0;i<root_fieldCount;++i)
{
const protobuf::FieldDescriptor* curFd = root_descriptor->field(i);
PrintField(root_message, curFd);
}
}

int main(int argc, char* argv[])
{
const char* test_filename = "person.txt";
fstream ifs(test_filename, ios::in | ios::binary);
tutorial::Person person_message;
person_message.ParseFromIstream(&ifs);
ifs.close();
IteratingWithDescriptor(person_message);
return 0;
}
예외처리도 안되어 있고, 소스 자체가 person 데이터 형식의 출력에 치우쳐있어서 다른 형식으로 직렬화된 버퍼는 바르게 출력하지 못할수 있습니다. Reflection의 사용법을 알려드리기 위한 예제이니 감안하고 봐주시기 바랍니다.

출력값은 아래와 같습니다.





핑백

덧글

댓글 입력 영역