json 对c++类的序列化(自动生成代码)
【动机】
之前写网络协议的时候,使用的是google protobuf,protobuf不但在性能和扩展性上有很好的优势,protoc自动生成c++类代码的工具,这点确实给程序员带来了很多便利。
做后面一项目使用的json格式来传输,然后就萌生了实现像protoc这样的工具,根据json文件来生成c++类代码,并且生成序列化代码,这样在写网络的时候就无需把jsonvalue序列化散落在各处。
【思路】
之前写object-c的时候,如果你要对类的序列化,你必须实现NSCoding协议(接口), 这样的实现方式很友好,同样,我的方式则是参考NSCoding的,
【Code】
我这里借鉴网友的一个json序列化实现方式,感觉这种方式很方便,他是通过模板来实现对内置类型的识别,而且对所有的类型都使用了统一接口:
/*
* Copyright (c) 2011-2012 Promit Roy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
//////////////////////////////////////////////////////////////
// From: http://ventspace.wordpress.com/2012/10/08/c-json-serialization/
// FileName: json_serializer_helper.hpp
// Modify: Sachin
// Date: 2013/9/22 13:41
// Description:
//
// History:
// <author> <time> <descript>
// Sachin 2013/9/22 add
////////////////////////////////////////////////////////////// #ifndef JSON_SERIALIZER_HELPER_HPP
#define JSON_SERIALIZER_HELPER_HPP
#include <lib_json/json_lib.h>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <string>
#include <assert.h> #define NVP(name) #name, name
#define SerializeNVP(name) Serialize(NVP(name)) #define DeSerializeNVP(name) DeSerialize(NVP(name)) class JsonSerializerHelper {
private:
//SFINAE garbage to detect whether a type has a Serialize member
struct serialize_not_found {};
typedef serialize_not_found SerializeNotFound;
struct SerializeFound { char x[]; }; template<typename T, void (T::*)(JsonSerializerHelper&) const>
struct SerializeTester { }; template<typename T>
static SerializeFound SerializeTest(SerializeTester<T, &T::Serialize>*);
template<typename T>
static SerializeNotFound SerializeTest(...); template<typename T>
struct HasSerialize
{
static const bool value = sizeof(SerializeTest<T>()) == sizeof(SerializeFound);
}; //Serialize using a free function defined for the type (default fallback)
template<typename TValue>
void SerializeImpl(const TValue& value,
typename boost::disable_if<HasSerialize<const TValue> >::type* dummy = )
{
//prototype for the serialize free function, so we will get a link error if it's missing
//this way we don't need a header with all the serialize functions for misc types (eg math)
void SerializeFail(const TValue&, JsonSerializerHelper&); SerializeFail(value, *this);
} //Serialize using a member function Serialize(JsonSerializer&)
template<typename TValue>
void SerializeImpl(const TValue& value, typename boost::enable_if<HasSerialize<const TValue> >::type* dummy = )
{
value.Serialize(*this);
} private:
//
struct deserialize_not_found {};
typedef deserialize_not_found DeSerializeNotFound; struct DeSerializeFound { char x[]; }; template<typename T, void (T::*)(const JsonSerializerHelper&)>
struct DeSerializeTester { };
template<typename T>
static DeSerializeFound DeSerializeTest(DeSerializeTester<T, &T::DeSerialize>*);
template<typename T>
static DeSerializeNotFound DeSerializeTest(...); template<typename T>
struct HasDeSerialize
{
static const bool value = sizeof(DeSerializeTest<T>()) == sizeof(DeSerializeFound);
}; //Serialize using a free function defined for the type (default fallback)
template<typename TValue>
void DeSerializeImpl(TValue& value,
typename boost::disable_if<HasDeSerialize<TValue> >::type* dummy = ) const
{
void DeSerializeFail(TValue&, const JsonSerializerHelper&); DeSerializeFail(value, *this);
} //Serialize using a member function Serialize(JsonSerializer&)
template<typename TValue>
void DeSerializeImpl(TValue& value, typename boost::enable_if<HasDeSerialize<TValue> >::type* dummy = ) const
{
value.DeSerialize(*this);
}
public:
JsonSerializerHelper()
{ } template<typename TKey, typename TValue>
void Serialize(TKey key, const TValue& value, typename boost::enable_if<boost::is_class<TValue> >::type* dummy = )
{
// class to json
JsonSerializerHelper subVal;
subVal.SerializeImpl(value);
JsonValue[key] = subVal.JsonValue;
} template<typename TKey, typename TValue>
void DeSerialize(TKey key, TValue& value, typename boost::enable_if<boost::is_class<TValue> >::type* dummy = ) const
{
// json to class
JsonSerializerHelper subVal;
subVal.JsonValue = JsonValue[key];
subVal.DeSerializeImpl(value);
} template<typename TKey>
void Serialize(TKey key, const Json::Value& value)
{
Write(key, value);
} template<typename TKey>
void DeSerialize(TKey key, Json::Value& value) const
{
Read(key, value);
}
//Serialize a string value
template<typename TKey>
void Serialize(TKey key, const std::string& value)
{
Write(key, value);
} //DeSerialize a string value
template<typename TKey>
void DeSerialize(TKey key, std::string& value) const
{
Read(key, value);
} //Serialize a non class type directly using JsonCpp
template<typename TKey, typename TValue>
void Serialize(TKey key, const TValue& value, typename boost::enable_if<boost::is_fundamental<TValue> >::type* dummy = )
{
Write(key, value);
} template<typename TKey, typename TValue>
void DeSerialize(TKey key, TValue& value, typename boost::enable_if<boost::is_fundamental<TValue> >::type* dummy = ) const
{
Read(key, value);
} //Serialize an enum type to JsonCpp
template<typename TKey, typename TEnum>
void Serialize(TKey key, const TEnum& value, typename boost::enable_if<boost::is_enum<TEnum> >::type* dummy = )
{
int ival = (int) value;
Write(key, ival);
} template<typename TKey, typename TEnum>
void DeSerialize(TKey key, TEnum& value, typename boost::enable_if<boost::is_enum<TEnum> >::type* dummy = ) const
{
int ival = (int) value;
Read(key, ival);
value = (TEnum) ival;
} template<typename TKey, typename TValue>
void Serialize(TKey key, const std::vector<TValue>& vec)
{
Write(key, vec.begin(), vec.end());
} template<typename TKey, typename TValue>
void DeSerialize(TKey key, std::vector<TValue>& vec) const
{
JsonSerializerHelper subVal;
subVal.JsonValue = JsonValue[key];
subVal.Read(vec);
} Json::Value JsonValue; private:
template<typename TKey, typename TValue>
void Write(TKey key, const TValue& value)
{
JsonValue[key] = value;
} template<typename TKey, typename TValue>
void Write(TKey key, const std::vector<TValue>& vec)
{ JsonSerializerHelper subVal;
int index = ;
for(typename std::vector<TValue>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
subVal.Serialize(index, *it);
++index;
}
JsonValue[key] = subVal.JsonValue;
} template<typename TKey, typename TItor>
void Write(TKey key, TItor first, TItor last)
{
JsonSerializerHelper subVal;
int index = ;
for(TItor it = first; it != last; ++it)
{
subVal.Serialize(index, *it);
++index;
}
JsonValue[key] = subVal.JsonValue;
} template<typename TKey, typename TValue>
void Read(TKey key, TValue& value, typename boost::enable_if<boost::is_arithmetic<TValue> >::type* dummy = ) const
{
int ival = ;
if (JsonValue[key].isNumeric()){
ival = JsonValue[key].asInt();
} else {
//assert(false);
}
value = (TValue) ival;
} template<typename TKey, typename TValue>
void Read(TKey key, TValue& value) const
{
value = JsonValue[key];
} template<typename TKey>
void Read(TKey key, bool& value) const
{
bool bval = false ;
bval = JsonValue[key].asBool();
value = bval;
} template<typename TKey>
void Read(TKey key, int& value) const
{
int ival = ;
if (JsonValue[key].isNumeric()){
ival = JsonValue[key].asInt();
} else if (JsonValue[key].isString()){
ival = atoi(JsonValue[key].asCString());
} else {
//assert(false);
}
value = ival;
} template<typename TKey>
void Read(TKey key, unsigned int& value) const
{
unsigned int uival = ;
if (JsonValue[key].isNumeric()){
uival = JsonValue[key].asUInt();
} else if (JsonValue[key].isString()){
uival = atoi(JsonValue[key].asCString());
} else {
//assert(false);
}
value = uival;
} template<typename TKey>
void Read(TKey key, float& value) const
{
float fval = 0.0 ;
if (JsonValue[key].isNumeric()){
fval = JsonValue[key].asFloat();
} else if (JsonValue[key].isString()){
fval = atof(JsonValue[key].asCString());
} else {
//assert(false);
}
value = fval;
} template<typename TKey>
void Read(TKey key, double& value) const
{
double dval = 0.0 ;
if (JsonValue[key].isNumeric()){
dval = JsonValue[key].asDouble();
} else if (JsonValue[key].isString()){
dval = atof(JsonValue[key].asCString());
} else {
//assert(false);
}
value = dval;
} template<typename TKey>
void Read(TKey key, std::string& value) const
{
std::string sval = "" ;
if (JsonValue[key].isString()){
sval = JsonValue[key].asString();
} else {
//assert(false);
}
value = sval;
} template<typename TValue>
void Read(std::vector<TValue>& vec) const
{
if(!JsonValue.isArray())
return; vec.clear();
vec.reserve(vec.size() + JsonValue.size());
for(int i = ; i < JsonValue.size(); ++i)
{
TValue val;
DeSerialize(i, val);
vec.push_back(val);
}
}
};
#endif //JSON_SERIALIZER_HELPER_HPP
我对原来的基础上进行了稍微改良,把DeSerialize 和Serialize分离了,每个类需要实现这两个接口,这个工具通过函数重载模板匹配对序列化做了统一的接口
【生成Cpp代码】
我们对json文件进行解析,json的dict对应c++的类,字典类的某个字段相应的类型对应c++类型,用key值作为class类型名,
【样例】
json
{
"image": {
"width": 800,
"height": 600,
"title": "View from 15th Floor",
"thumbnail": {
"url": "http://www.example.com/image/481989943",
"height": 125,
"width": "100"
},
"ids": [116, 943, 234, 38793]
}
}
c++ cpp
// Don't Edit it
#ifndef TEST_H_
#define TEST_H_ #include <string>
#include <vector>
#include <lib_json/json_lib.h> class JsonSerializerHelper; namespace net {
namespace test { class Thumbnail {
public:
Thumbnail();
~Thumbnail(){} const std::string& get_url() { return url;}
const std::string& get_url() const { return url;}
void set_url(const std::string& url_a) {
url = url_a;
} const std::string& get_width() { return width;}
const std::string& get_width() const { return width;}
void set_width(const std::string& width_a) {
width = width_a;
} const int& get_height() { return height;}
const int& get_height() const { return height;}
void set_height(const int& height_a) {
height = height_a;
} void Serialize(JsonSerializerHelper& json_serializer_helper) const;
void DeSerialize(const JsonSerializerHelper& json_serializer_helper); private:
std::string url;
std::string width;
int height; }; // class Thumbnail class Image {
public:
Image();
~Image(){} const std::vector<int>& get_ids() { return ids;}
const std::vector<int>& get_ids() const { return ids;}
void set_ids(const std::vector<int>& ids_a) {
ids = ids_a;
} const int& get_width() { return width;}
const int& get_width() const { return width;}
void set_width(const int& width_a) {
width = width_a;
} const std::string& get_title() { return title;}
const std::string& get_title() const { return title;}
void set_title(const std::string& title_a) {
title = title_a;
} Thumbnail& get_thumbnail() { return thumbnail;}
const Thumbnail& get_thumbnail() const { return thumbnail;}
void set_thumbnail(const Thumbnail& thumbnail_a) {
thumbnail = thumbnail_a;
} const int& get_height() { return height;}
const int& get_height() const { return height;}
void set_height(const int& height_a) {
height = height_a;
} void Serialize(JsonSerializerHelper& json_serializer_helper) const;
void DeSerialize(const JsonSerializerHelper& json_serializer_helper); private:
std::vector<int> ids;
int width;
std::string title;
Thumbnail thumbnail;
int height; }; // class Image class Test {
public:
Test();
~Test(){} Image& get_image() { return image;}
const Image& get_image() const { return image;}
void set_image(const Image& image_a) {
image = image_a;
} void Serialize(JsonSerializerHelper& json_serializer_helper) const;
void DeSerialize(const JsonSerializerHelper& json_serializer_helper); private:
Image image; }; // class Test } // namespace test
} // namespace net
#endif // TEST_H_
//Don't Edit it #include "test.h"
#include "network/net_util/json_serializer_helper.hpp" namespace net {
namespace test { Thumbnail::Thumbnail(): height(){
} void Thumbnail::Serialize(
JsonSerializerHelper& json_serializer_helper) const {
json_serializer_helper.SerializeNVP(url);
json_serializer_helper.SerializeNVP(width);
json_serializer_helper.SerializeNVP(height);
} void Thumbnail::DeSerialize(
const JsonSerializerHelper& json_serializer_helper) {
json_serializer_helper.DeSerializeNVP(url);
json_serializer_helper.DeSerializeNVP(width);
json_serializer_helper.DeSerializeNVP(height);
} Image::Image(): width(),
height(){
} void Image::Serialize(
JsonSerializerHelper& json_serializer_helper) const {
json_serializer_helper.SerializeNVP(ids);
json_serializer_helper.SerializeNVP(width);
json_serializer_helper.SerializeNVP(title);
json_serializer_helper.SerializeNVP(thumbnail);
json_serializer_helper.SerializeNVP(height);
} void Image::DeSerialize(
const JsonSerializerHelper& json_serializer_helper) {
json_serializer_helper.DeSerializeNVP(ids);
json_serializer_helper.DeSerializeNVP(width);
json_serializer_helper.DeSerializeNVP(title);
json_serializer_helper.DeSerializeNVP(thumbnail);
json_serializer_helper.DeSerializeNVP(height);
} Test::Test(){
} void Test::Serialize(
JsonSerializerHelper& json_serializer_helper) const {
json_serializer_helper.SerializeNVP(image);
} void Test::DeSerialize(
const JsonSerializerHelper& json_serializer_helper) {
json_serializer_helper.DeSerializeNVP(image);
} } // namespace test
} // namespace net
【注意】
1.因为json支持数组支持不同类型的值,但c++不支持,所有我这里数组里面只认识写简单的类型,但要类型一致,
2.这里用key的首字母大写做类型名,用key值作为对象名,所以一定要保证首字母key是小写的
3.因为不同json可能有相同的key值,所以我针对不同的json加了namespace 保护
以上的问题,我们在开发过程中,这样的需求很少,即使有,我们也去避开这样的问题。不是去正面对抗这样的问题。因为我要自动生成解析代码,自动生成好处是自动更新,无需人为参与。
【GitHub】
https://github.com/SachinKung/json2cpp
json 对c++类的序列化(自动生成代码)的更多相关文章
- mybatis 自动生成代码(mybatis generator)
pom.xml 文件配置 引入 mybatis generator <properties> <mysql.connector.version>5.1.44</mysql ...
- mybatis generator maven插件自动生成代码
如果你正为无聊Dao代码的编写感到苦恼,如果你正为怕一个单词拼错导致Dao操作失败而感到苦恼,那么就可以考虑一些Mybatis generator这个差价,它会帮我们自动生成代码,类似于Hiberna ...
- MyBatis自动生成代码示例
在项目中使用到mybatis时,都会选择自动生成实体类,Mapper,SqlMap这三个东东. 手头上在用的又不方便,找了下网上,其实有很多文章,但有些引用外部文件时不成功,也不方便,所以重新整理了下 ...
- MyBatis使用Generator自动生成代码
MyBatis中,可以使用Generator自动生成代码,包括DAO层. MODEL层 .MAPPING SQL映射文件. 第一步: 配置好自动生成代码所需的XML配置文件,例如(generator. ...
- 【MyBatis】MyBatis自动生成代码查询之爬坑记
前言 项目使用SSM框架搭建Web后台服务,前台后使用restful api,后台使用MyBatisGenerator自动生成代码,在前台使用关键字进行查询时,遇到了一些很宝贵的坑,现记录如下.为展示 ...
- mybatis-generator自动生成代码插件
mybatis自动生成代码(实体类.Dao接口等)是很成熟的了,就是使用mybatis-generator插件. 它是一个开源的插件,使用maven构建最好,可以很方便的执行 插件官方简介: http ...
- (Python)自动生成代码(方法一)
在写某个平台的自动化脚本时,笔者把全部的操作都封装到了两个类中,page.py和commonpage.py: page.py部分代码: class BasePage(object): ''' 页面基础 ...
- SpringBoot 添加mybatis generator 自动生成代码插件
自动生成数据层代码,提高开发效率 1.pom添加插件,并指定配置文件路径 <!-- mybatis generator 自动生成代码插件 --> <plugin> <gr ...
- springboot学习随笔(四):Springboot整合mybatis(含generator自动生成代码)
这章我们将通过springboot整合mybatis来操作数据库 以下内容分为两部分,一部分主要介绍generator自动生成代码,生成model.dao层接口.dao接口对应的sql配置文件 第一部 ...
随机推荐
- Java重点之小白解析--浅谈HashMap与HashTable
这是一个面试经常遇到的知识点,无论什么公司这个知识点几乎是考小白必备,为什么呢?因为这玩意儿太特么常见了,常见到你写一百行代码,都能用到好几次,不问这个问哪个.so!本小白网罗天下HashMap与Ha ...
- JS之模块模式应用
之前做过一些简单的单页面应用项目,是对模块模式很好的应用,我决定动手做一个简单的Demo出来. 基本思想是设计一个加载器,当用户点击菜单时,获取不同选项的按钮id,根据不同id实现对页面内容的替换. ...
- Mongodb 服务(windows环境下)因被强制关闭,导致服务不能启动的处理办法
环境:windows 8操作系统下 前置条件:因操作系统原因,没有先停止mongodb服务,直接重启操作系统. 导致结果:mongodb服务无法启动,弹出框报错. Windows 无法启动MongoD ...
- WCF权限控制
前面写了 WCF账户密码认证, 实现了帐号密码认证, 接下来看看如何对方法的细粒度控制, 本文很大程度参考了 WCF安全之基于自定义声明授权策略, 这篇文章对原理讲得比较清楚, 而我这篇文章呢, ...
- SQL Server日期时间格式转换字符串详解 (详询请加qq:2085920154)
在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...
- display转块状化
display:block block元素会独占一行,多个block元素会各自新起一行.默认情况下,block元素宽度自动填满其父元素宽度. block元素 ...
- EXCEL文件格式不匹配,或者已经损坏,除非信任来源
修改注册表解决: .打开注册表编辑器 方法:开始 -> 运行 -> 输入regedit -> 确定 .找到注册表子项 HKEY_CURRENT_USER\Software\Micro ...
- SQL脚本IN在EF中的应用
C#查询条件中存在in,为了避免拼脚本,参数化查询数据库,提高安全性,规避脚本注入.网上找了好多,最后发现 SqlParameter 是无法实现in的操作,所以只能变相来实现,结果还是不错的,性能上各 ...
- js二维数组与字符串
1. 二维数组:数组中的元素,又引用了另一个数组对象 何时使用:只要保存横行竖列的数据, 具有上下级包含关系的数据, 创建二维数组: 1. var arr=[]; col arr[0]=[" ...
- HttpWebRequest类
HttpWebRequest类与HttpRequest类的区别. HttpRequest类的对象用于服务器端,获取客户端传来的请求的信息,包括HTTP报文传送过来的所有信息.而HttpWebReque ...