C++对象的JSON序列化与反序列化探索

一:背景

作为一名C++开发人员,我一直很期待能够像C#JAVA那样,可以轻松的进行对象的序列化与反序列化,但到目前为止,尚未找到相对完美的解决方案。

本文旨在抛砖引玉,期待有更好的解决方案;同时向大家寻求帮助,解决本文中未解决的问题。 

二:相关技术介绍

本方案采用JsonCpp来做具体的JSON的读入与输出,再结合类成员变量的映射,最终实现对象的JSON序列化与反序列化。

本文不再讨论如何使用JsonCpp,此处将作者在应用时发现的两处问题进行说明:

1.       下载Jsoncpp,编译其lib,并且引用到项目中,发现有如下错误:

错误1       fatal error C1083: Cannot open compiler generated file: '../../build/vs71/release/lib_json\json_writer.asm': No such file or directory       c:\Documents and Settings\Administrator\jsoncpp-src-0.6.0-rc2\jsoncpp-src-0.6.0-rc2\src\lib_json\json_writer.cpp

错误2       fatal error LNK1257: 代码生成失败     JasonSerialize 

 

 可以通过在修改LIB库项目的属性解决,如下图[关闭汇编输出]

C++对象的JSON序列化与反序列化探索

2.      JSONCPP官网首页的下载版本是0.5.0,此版本不支持Int64等类型,下载版本jsoncpp-src-0.6.0-rc2后即可支持. 

三:一个基于JsonCpp的序列化与反序列化基类

先看代码:

#pragma once

#include <string>

#include <vector>

#include "json/json.h"

using std::string;

using std::vector;

struct CJsonObejectBase

{

protected:

	enum CEnumJsonTypeMap

	{

		asInt = 1,

		asUInt,

		asString,

		asInt64,

		asUInt64,

	};

public:

	CJsonObejectBase(void){}

public:

	virtual ~CJsonObejectBase(void){}

	string Serialize()

	{

		Json::Value new_item;  

		int nSize = m_listName.size();

		for (int i=0; i < nSize; ++i )

		{

			void* pAddr = m_listPropertyAddr[i];

			switch(m_listType[i])

			{

			case asInt:

				new_item[m_listName[i]] = (*(INT*)pAddr);

				break;

			case asUInt:

				new_item[m_listName[i]] = (*(UINT*)pAddr);

				break;

			case asInt64:

				new_item[m_listName[i]] = (*(LONGLONG*)pAddr);

				break;

			case asUInt64:

				new_item[m_listName[i]] = (*(ULONGLONG*)pAddr);

				break;

			case asString:

				new_item[m_listName[i]] = (*(string*)pAddr);

			default:

				//我暂时只支持这几种类型,需要的可以自行添加 

				break;

			}		

		}

		Json::FastWriter writer;  

		std::string out2 = writer.write(new_item); 

		return out2;

	}



	bool DeSerialize(const char* str)

	{

		Json::Reader reader;  

		Json::Value root;

		if (reader.parse(str, root))

		{  

			int nSize = m_listName.size();

			for (int i=0; i < nSize; ++i )

			{

				void* pAddr = m_listPropertyAddr[i];



				switch(m_listType[i])

				{

				case asInt:

					(*(INT*)pAddr) = root.get(m_listName[i], 0).asInt();

					break;

				case asUInt:

					(*(UINT*)pAddr) = root.get(m_listName[i], 0).asUInt();

					break;

				case asInt64:

					(*(LONGLONG*)pAddr) = root.get(m_listName[i], 0).asInt64();

					break;

				case asUInt64:

					(*(ULONGLONG*)pAddr) = root.get(m_listName[i], 0).asUInt64();

					break;

				case asString:

					(*(string*)pAddr) = root.get(m_listName[i], "").asString();

				default:

					//我暂时只支持这几种类型,需要的可以自行添加 

					break;

				}			

			}

			return true;

		}

		return false;

	}

protected:

	void SetProperty(string name, CEnumJsonTypeMap type, void* addr)

	{

		m_listName.push_back(name);

		m_listPropertyAddr.push_back(addr);

		m_listType.push_back(type);

	}

	virtual void SetPropertys() = 0;

	vector<string> m_listName;

	vector<void*>  m_listPropertyAddr;

	vector<CEnumJsonTypeMap>	   m_listType;

};

此类主要有三个函数:Serialize、DeSerialize及 SetPropertys、SetProperty,其中前两个函数主要是用来实现对象的序列化与反序列化;SetPropertys是一个纯虚函数,如果一个类需要具备序列化功能,只需要从此类继承,同时调用SetProperty函数,将各个字段的属性进行设置即可。  

四:使用对象的序列化及反序列化功能

要使对象具体相应功能,需要继承上述的基类,如下: 

struct CTestStruct : public CJsonObejectBase

{

	CTestStruct()

	{

		SetPropertys();

	}

	ULONGLONG MsgID;

	string MsgTitle;

	string MsgContent;

protected:

	//子类需要实现此函数,并且将相应的映射关系进行设置 

	virtual void SetPropertys()

	{

		SetProperty("MsgID", asUInt64, &MsgID);

		SetProperty("MsgTitle", asString, &MsgTitle);

		SetProperty("MsgContent", asString, &MsgContent);

	}

};

继承后,我们可以使用如下代码来进行测试

序列化: 

void CJasonSerializeDlg::OnBnClickedOk()

{

	CTestStruct stru;

	stru.MsgID = 11223344;

	stru.MsgTitle = "黑黑";

	stru.MsgContent = "哈哈";

	CString strTest = stru.Serialize().c_str();

	AfxMessageBox(strTest);

}

结果:

C++对象的JSON序列化与反序列化探索

反序列化: 

void CJasonSerializeDlg::OnBnClickedOk2()

{

	const char* pstr = "{\"MsgContent\":\"哈哈22\",\"MsgID\":11111111111111111,\"MsgTitle\":\"黑黑22\"}";

	CTestStruct stru;

	stru.DeSerialize(pstr);

	CString strShow = "";

	strShow.Format("MsgID:%I64u\r\nMsgTile:%s\r\nMsgContent:%s", stru.MsgID, stru.MsgTitle.c_str(), stru.MsgContent.c_str());

	AfxMessageBox(strShow);

}

结果:

C++对象的JSON序列化与反序列化探索 

五:未解决的问题

1.       目前我对属性的映射采用的是vector顺序映射的方式,这样必需在子类中对每一个属性进行设置,是否有宏的策略可以使这部分工作更加轻松?

2.       目前只支持整型、64位整型及字符串类型,需要支持其他类型,可以在基类中添加映射即可。

3.       目前只支持单个简单对象[其属性均为简单类型]的序列化与反序列化,暂时未考虑如何支持复杂的,如内部包含其他的复杂对象、包含数组等情况。 

完整代码请于如下链接下载:

 http://download.csdn.net/detail/tragicguy/5630473

你可能感兴趣的:(json)