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

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 库项目的属性解决,如下图 [ 关闭汇编输出 ]

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);
}

结果:

反序列化:  

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);
}

结果:

 

五:未解决的问题

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

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

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

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

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

转载于:https://my.oschina.net/u/727148/blog/706233

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值