Converting C++ class to JSON

前端 未结 11 856
轮回少年
轮回少年 2020-12-02 11:56

I\'d like to create a JSON string containing the instance variables of my class.

For example,

class Example {  
    std::string string;  
    std::ma         


        
相关标签:
11条回答
  • 2020-12-02 12:34

    In RareCpp I've created a very effective JSON Library on top of a reflection implementation. It's written for C++17 and works with Visual Studios, g++, and Clang. The library is header only, meaning you need only copy the reflect and json headers into your project to use it.

    The JSON library only requires that you list the fields once in the REFLECT macro; from there it auto identifies appropriate JSON output representations for reading or writing, and can recursively traverse any reflected fields, as well as arrays, STL containers, references, pointers, and more.

    struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
    struct MyObject
    {
        int myInt;
        std::string myString;
        MyOtherObject myOtherObject;
        std::vector<int> myIntCollection;
    
        REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
    };
    
    int main()
    {
        MyObject myObject = {};
        std::cout << "Enter MyObject:" << std::endl;
        std::cin >> Json::in(myObject);
        std::cout << std::endl << std::endl << "You entered:" << std::endl;
        std::cout << Json::pretty(myObject);
    }
    

    The above could be ran like so...

    Enter MyObject:
    {
      "myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
      "myOtherObject": {
        "myOtherInt": 9001
      }
    }
    
    
    You entered:
    {
      "myInt": 1337,
      "myString": "stringy",
      "myOtherObject": {
        "myOtherInt": 9001
      },
      "myIntCollection": [ 2, 4, 6 ]
    }
    

    You can also annotate fields to do things like give them a different name in the JSON representation, force them to be strings, and so on.

    struct Point
    {
        NOTE(latitude, Json::Name{"lat"})
        double latitude;
    
        NOTE(longitude, Json::Name{"long"})
        double longitude;
    
        REFLECT(Point, latitude, longitude)
    };
    

    See here for more examples, there are many other features such as capturing super classes, support for reading, traversing, and writing JSON not known at compile time, further customizing JSON representations for specific fields or types, and more.

    0 讨论(0)
  • 2020-12-02 12:35

    I wrote a library which designed to solve your problem. However, it is a very new project, not stable enough. Feel free to take a look, the homepage is here::

    https://github.com/Mizuchi/acml

    In your example, you have to add one line like this:

    ACML_REGISTER(Example, ,(string)(map)(vector));
    

    in order to tell the library which member you want to dump. Since C++ have no reflection. And you must give a way to access the member, either use public member level or use friend class.

    And later you just need to do sth like this:

    string result = acml::json::dumps(any_object);

    would become::

    {
        "string": "the-string-value",
        "map":
        {
            "key1": "val1",
            "key2": "val2"
        },
        "vector":
        {
            "type": "std::vector",
            "size": "4",
            "0": "1",
            "1": "2",
            "2": "3",
            "3": "4"
        }
    }
    

    As you see, JSON array is not implemented yet. And everything becomes string now.

    0 讨论(0)
  • 2020-12-02 12:35

    nlohmann::json allows you to have arbitrary type conversions. It's described here https://nlohmann.github.io/json/features/arbitrary_types/ in more detail.

    class Example {  
        std::string string;  
        std::map<std::string, std:string> map;  
        std::vector<int> vector;
    
        // Add this to your code.
        NLOHMANN_DEFINE_TYPE_INTRUSIVE(Example, string, map, vector);
    };
    

    Since the class members are private you can use the macro: NLOHMANN_DEFINE_TYPE_INTRUSIVE(...). I don't know whether it works with std::map or std::vector but it works with primitive types.

    Like here:

    struct MyStruct {
        std::string name;
        int number;
    
        NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MyStruct, name, number);
    };
    

    Note how I used NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE because the struct members are public.

    Now I can call the to_json(Json& j, const MyStruct& s) function like:

    MyStruct s;
    s.name = "test";
    s.number = 11;
    
    nlohmann::json j;
    s.to_json(j, s);
    std::cout << j << std::endl;
    // {"name":"test","number":11}
    
    0 讨论(0)
  • 2020-12-02 12:38

    this python script generates c++ pod classes with one member for each json property

    you want quite the opposite thing, but is trivial to generate a mapping class which does both loading and saving

    generated code relies on an external json parser library

    0 讨论(0)
  • 2020-12-02 12:42

    I have written an experimental library that can do the job, but it requires external description of classes structures and hierarchy. It uses GCCXML to build an xml dictionary, used for serialization de-serialization :

    http://code.google.com/p/cjson/

    It's for the moment an experimental project, that can deals with fundamental types (int, float double), pointers to fundamentals types, classes, inherited members etc ... It implements basic std::vector ans std::map serialization, and also std::string instances.

    See details for implementation here

    0 讨论(0)
提交回复
热议问题