首页 > 代码库 > json 对c++类的序列化(自动生成代码)

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[2]; };  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 = http://www.mamicode.com/sizeof(SerializeTest<T>(0)) == 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 = 0)  {    //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 = 0)  {    value.Serialize(*this);  } private:  //    struct deserialize_not_found {};  typedef deserialize_not_found DeSerializeNotFound;  struct DeSerializeFound { char x[2]; };    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 = http://www.mamicode.com/sizeof(DeSerializeTest<T>(0)) == 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 = 0) 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 = 0) 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 = 0)  {    // 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 = 0) 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 = 0)  {        Write(key, value);  }  template<typename TKey, typename TValue>  void DeSerialize(TKey key, TValue& value, typename boost::enable_if<boost::is_fundamental<TValue> >::type* dummy = 0) 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 = 0)  {    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 = 0) 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 = 0;    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 = 0;    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 = 0) const  {        int ival = 0 ;    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 = 0 ;    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 = 0 ;    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 = 0; i < JsonValue.size(); ++i)    {      TValue val;      DeSerialize(i, val);      vec.push_back(val);    }  }};#endif //JSON_SERIALIZER_HELPER_HPP
View Code

 

 

 我对原来的基础上进行了稍微改良,把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]     }}
View Code

 

  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 Thumbnailclass 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 Imageclass 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_
View Code

 

【注意】

  1.因为json支持数组支持不同类型的值,但c++不支持,所有我这里数组里面只认识写简单的类型,但要类型一致,

      2.这里用key的首字母大写做类型名,用key值作为对象名,所以一定要保证首字母key是小写的

      3.因为不同json可能有相同的key值,所以我针对不同的json加了namespace 保护

  以上的问题,我们在开发过程中,这样的需求很少,即使有,我们也去避开这样的问题。不是去正面对抗这样的问题。因为我要自动生成解析代码,自动生成好处是自动更新,无需人为参与。

【GitHub】

https://github.com/SachinKung/json2cpp