• 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 = 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 = 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 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_
    View Code
    //Don't Edit it
    
    #include "test.h"
    #include "network/net_util/json_serializer_helper.hpp"
    
    
    namespace net {
    namespace test {
    
    Thumbnail::Thumbnail():        height(0){
    }
    
    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(0),
            height(0){
    }
    
    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
    View Code

    【注意】

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

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

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

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

    【GitHub】

    https://github.com/SachinKung/json2cpp

       

      

  • 相关阅读:
    Glide加载网络图片与本地图片尺寸不一致
    android BLE 40 setCharacteristicNotification接收不到数据
    Android中颜色透明度对应16进制值
    模拟器不能运行 Failed to start emulator: Cannot run program "/home/kroaity/Downloads/android-sdk-linux//tools/emulator": error=2
    android SDK Manager 代理服务器设置
    if the parser found inconsistent certificates on the files in the .apk.104
    win7自带桌面便签
    unable to connect to the virtual device Genymotion 神器启动问题
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    获得root权限system/app下文件无法删除
  • 原文地址:https://www.cnblogs.com/sachin/p/3762773.html
Copyright © 2020-2023  润新知