为了一些项目的需要,可能需要google protobuf 的Message结构与Json结构进行互转。我本人也在近期的项目中使用到这个,虽然可以自己写代码一个变量一个变量的进行转化,但终究觉得使用自动化处理会更好,一步到位,其他的成分就只是处理逻辑罢了。因此在项目中做了一个简单的封装,并且已经得到了项目的验证。今天先将protobuf Message转Json结构的代码献上,供大家玩味吐槽,下一篇博客将供上Json转Protobuf的代码。
Json的第三方库目前很多,并且也大部分使用比较简单,我个人使用的是Json cpp。
在Json与google protobuf Message互转必然会使用到google protobuf的反射机制,如果各朋友对于此不是很熟悉,看代码也可略知一二。如果想了解更详细,可以参照google的官方文档或者参照各位大大的博客,很多博客写的异常到位,况且可以相互交流。当然网上肯定也有各种大牛写的两者互转的代码,大家也可借鉴https://github.com/shramov/json2pb。好像csdn上同样可以下载。下面奉上小弟的代码:
#include "json/json.h"
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
using namespace ::google::protobuf;
void FormatToJson(Json::Value& value, const ::google::protobuf::Message& msg)
{
const Descriptor* descriptor = msg.GetDescriptor();
const Reflection* reflection = msg.GetReflection();
const int count = descriptor->field_count();
for (int i = 0; i < count; ++i)
{
const FieldDescriptor* field = descriptor->field(i);
if (field->is_repeated())
{
if (reflection->FieldSize(msg, field) > 0)
{
FormatRepeatedField(value[field->name()], msg, field, reflection);
}
continue;
}
if (!reflection->HasField(msg, field))
{
continue;
}
switch (field->type())
{
case FieldDescriptor::TYPE_MESSAGE:
{
const Message& tmp_msg = reflection->GetMessage(msg, field);
if (0 != tmp_msg.ByteSize())
{
FormatToJson(value[field->name()], tmp_msg);
}
}
break;
case FieldDescriptor::TYPE_INT32:
value[field->name()] = reflection->GetInt32(msg, field);
break;
case FieldDescriptor::TYPE_UINT32:
value[field->name()] = reflection->GetUInt32(msg, field);
break;
case FieldDescriptor::TYPE_INT64:
{
static char int64str[25];
memset(int64str, 0, sizeof(int64str));
snprintf(int64str, sizeof(int64str), "%lld", (long long)reflection->GetInt64(msg, field));
value[field->name()] = int64str;
}
break;
case FieldDescriptor::TYPE_UINT64:
{
static char uint64str[25];
memset(uint64str, 0, sizeof(uint64str));
snprintf(uint64str, sizeof(uint64str), "%llu", (unsigned long long)reflection->GetUInt64(msg, field));
value[field->name()] = uint64str;
}
break;
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
{
value[field->name()] = reflection->GetString(msg, field);
}
break;
default:
break;
}
}
}
void FormatRepeatedField(Json::Value& value, const ::google::protobuf::Message& msg, const google::protobuf::FieldDescriptor *field, const ::google::protobuf::Reflection *reflection)
{
if (NULL == field || NULL == reflection)
{
FormatToJson(value, msg);
}
for (int i = 0; i < reflection->FieldSize(msg, field); ++i)
{
Json::Value tmp_value;
switch (field->type())
{
case FieldDescriptor::TYPE_MESSAGE:
{
const Message& tmp_msg = reflection->GetRepeatedMessage(msg, field, i);
if (0 != tmp_msg.ByteSize())
{
FormatToJson(tmp_value, tmp_msg);
}
}
break;
case FieldDescriptor::TYPE_INT32:
tmp_value = reflection->GetRepeatedInt32(msg, field, i);
break;
case FieldDescriptor::TYPE_UINT32:
tmp_value = reflection->GetRepeatedUInt32(msg, field, i);
break;
case FieldDescriptor::TYPE_INT64:
{
static char int64str[25];
memset(int64str, 0, sizeof(int64str));
snprintf(int64str, sizeof(int64str), "%lld", (long long)reflection->GetRepeatedInt64(msg, field, i));
tmp_value = int64str;
}
break;
case FieldDescriptor::TYPE_UINT64:
{
static char uint64str[25];
memset(uint64str, 0, sizeof(uint64str));
snprintf(uint64str, sizeof(uint64str), "%llu", (unsigned long long)reflection->GetRepeatedUInt64(msg, field, i));
tmp_value = uint64str;
}
break;
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
tmp_value = reflection->GetRepeatedString(msg, field, i);
break;
default:
break;
}
value.append(tmp_value);
}
}
上述代码说明:
1 在我用的Json cpp的版本中,好像不支持64位数字,因此对于64位数字转换成字符串型
2. 该代码是我自己写的项目使用,或许有很多考虑不周的地方,欢迎拍砖。