天天看点

c++使用Protobuf Message转Json字符串(Json库使用Json cpp)

为了一些项目的需要,可能需要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. 该代码是我自己写的项目使用,或许有很多考虑不周的地方,欢迎拍砖。