Serialization - GitMasterNikanjam/nlohmann_json_examples GitHub Wiki

JSON serialization refers to the process of converting data structures (such as C++ objects, arrays, maps, etc.) into a JSON string format that can be stored, transferred, or shared. Deserialization is the reverse process—converting a JSON string back into a usable data structure in C++.

Key Concepts in JSON Serialization with nlohmann/json

The nlohmann/json library makes it very easy to serialize and deserialize data in C++ to and from JSON. Let's break down serialization in more detail.

1. Serializing Basic JSON Data Types

In nlohmann/json, you can serialize a variety of basic data types (like integers, strings, booleans, arrays, and objects) directly into JSON format.

Example of Serializing a JSON Object:

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
    // Creating a JSON object
    json j;
    j["name"] = "Alice";
    j["age"] = 25;
    j["is_student"] = true;
    j["skills"] = {"C++", "Python", "JavaScript"};

    // Serialize JSON object to string
    std::string serialized = j.dump();
    std::cout << "Serialized JSON: " << serialized << std::endl;

    return 0;
}

Output:

Serialized JSON: {"age":25,"is_student":true,"name":"Alice","skills":["C++","Python","JavaScript"]}

In the example above, the dump() method converts the JSON object into a serialized JSON string.

2. Pretty-Printing (Formatted Serialization)

By default, the serialized string is compact, but you can also pretty-print (format) the output using the dump() method with indentation:

std::string pretty = j.dump(4);  // 4 spaces indentation
std::cout << "Pretty-printed JSON:\n" << pretty << std::endl;

Output:

Pretty-printed JSON:
{
    "age": 25,
    "is_student": true,
    "name": "Alice",
    "skills": [
        "C++",
        "Python",
        "JavaScript"
    ]
}

3. Serializing Complex and Nested Data Structures

You can serialize more complex data structures that contain nested objects or arrays. For example:

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
    // Nested JSON object
    json j;
    j["person"] = {
        {"name", "Bob"},
        {"age", 30},
        {"is_student", false}
    };
    j["person"]["skills"] = {"C++", "Python"};
    
    // Serialize the complex JSON object
    std::string serialized = j.dump(4);
    std::cout << "Serialized JSON:\n" << serialized << std::endl;

    return 0;
}

Output:

{
    "person": {
        "age": 30,
        "is_student": false,
        "name": "Bob",
        "skills": [
            "C++",
            "Python"
        ]
    }
}

4. Serialization to Files

To store serialized JSON data into a file, you can write the string result of dump() into a file stream.

#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
    json j;
    j["name"] = "Alice";
    j["age"] = 25;
    j["is_student"] = true;

    // Serialize and write to file
    std::ofstream file("output.json");
    file << j.dump(4);  // Pretty-print with 4-space indentation
    file.close();

    std::cout << "JSON written to file!" << std::endl;
    return 0;
}

This will create an output.json file with the serialized JSON content.

5. Serializing Custom C++ Types (User-Defined Classes)

To serialize and deserialize custom C++ types, you need to implement special to_json and from_json functions. This allows you to convert your own classes and structures to and from JSON.

Step 1: Define a Custom C++ Class

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

class Person {
public:
    std::string name;
    int age;
    bool is_student;

    Person(std::string n, int a, bool s) : name(n), age(a), is_student(s) {}
};

Step 2: Implement to_json and from_json Functions

You need to define two functions for converting between your class and JSON:

// Convert from Person object to JSON
void to_json(json& j, const Person& p) {
    j = json{{"name", p.name}, {"age", p.age}, {"is_student", p.is_student}};
}

// Convert from JSON to Person object
void from_json(const json

```cpp
& j, Person& p) {
    j.at("name").get_to(p.name);
    j.at("age").get_to(p.age);
    j.at("is_student").get_to(p.is_student);
}

Step 3: Using the Custom Class with JSON Serialization

Now, you can easily serialize and deserialize objects of your custom class using the nlohmann::json library:

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

class Person {
public:
    std::string name;
    int age;
    bool is_student;

    Person(std::string n, int a, bool s) : name(n), age(a), is_student(s) {}
};

// Define the to_json and from_json functions
void to_json(json& j, const Person& p) {
    j = json{{"name", p.name}, {"age", p.age}, {"is_student", p.is_student}};
}

void from_json(const json& j, Person& p) {
    j.at("name").get_to(p.name);
    j.at("age").get_to(p.age);
    j.at("is_student").get_to(p.is_student);
}

int main() {
    // Create a Person object
    Person alice("Alice", 25, true);

    // Serialize the Person object to JSON
    json j = alice;
    std::cout << "Serialized JSON:\n" << j.dump(4) << std::endl;

    // Deserialize the JSON back to a Person object
    Person new_person = j.get<Person>();
    std::cout << "\nDeserialized Person:\n";
    std::cout << "Name: " << new_person.name << "\n";
    std::cout << "Age: " << new_person.age << "\n";
    std::cout << "Is Student: " << std::boolalpha << new_person.is_student << std::endl;

    return 0;
}

Output:

Serialized JSON:
{
    "age": 25,
    "is_student": true,
    "name": "Alice"
}

Deserialized Person:
Name: Alice
Age: 25
Is Student: true

6. Custom Serialization for More Complex Objects

For more complex objects, such as those containing nested objects, arrays, or other custom types, the to_json and from_json functions can be expanded to handle these cases. For example, if Person had a list of skills:

class Person {
public:
    std::string name;
    int age;
    bool is_student;
    std::vector<std::string> skills;

    Person(std::string n, int a, bool s, std::vector<std::string> sk)
        : name(n), age(a), is_student(s), skills(sk) {}
};

void to_json(json& j, const Person& p) {
    j = json{{"name", p.name}, {"age", p.age}, {"is_student", p.is_student}, {"skills", p.skills}};
}

void from_json(const json& j, Person& p) {
    j.at("name").get_to(p.name);
    j.at("age").get_to(p.age);
    j.at("is_student").get_to(p.is_student);
    j.at("skills").get_to(p.skills);
}

7. Performance Considerations

While JSON serialization is flexible and human-readable, it's slower than binary formats. If performance is a priority (e.g., for high-frequency data exchanges), consider more compact formats such as MessagePack or Protocol Buffers. However, for most general purposes where JSON is favored for its readability, nlohmann/json offers a good balance between ease of use and performance.

Conclusion

  • Serialization with nlohmann/json is straightforward: you use dump() to convert objects into JSON strings.
  • You can pretty-print JSON with indentation by passing an argument to dump().
  • Custom classes require implementing to_json and from_json functions, enabling seamless integration with JSON serialization and deserialization.
  • The library provides a flexible and powerful toolset for both simple and complex serialization needs, making it a popular choice for C++ projects dealing with JSON.
⚠️ **GitHub.com Fallback** ⚠️