nlohmann/json

SerializationC++JSONHeader-onlyModern C++Type-safe

Library

nlohmann/json

Overview

nlohmann/json is the most popular JSON library designed for modern C++. It aims to treat JSON data as a first-class citizen in C++, providing an intuitive API and rich functionality. Usable by including a single header file, it allows JSON manipulation with an STL-like feel. With its focus on type safety and ease of use, it has become the de facto standard for JSON processing in C++ projects.

Details

nlohmann/json is a header-only JSON library developed leveraging C++11 and later features. It supports all JSON features (objects, arrays, strings, numbers, booleans, null) and provides advanced functionality such as automatic type inference, custom type serialization, SAX/DOM-style parsing, JSON pointers, and JSON patches. The design philosophy is "ease of use first," providing an interface that C++ programmers can use intuitively.

Key Features

  • Header-only: Complete in a single file, no build configuration required
  • STL-like: Intuitive operation similar to vector or map
  • Type safety: Deep integration with C++ type system
  • Rich functionality: JSON pointer, JSON patch, MessagePack/CBOR/UBJSON support
  • Customizable: Automatic serialization for user-defined types
  • Exception safe: Provides strong exception guarantees

Advantages and Disadvantages

Advantages

  • Extremely intuitive and easy-to-use API design
  • Easy to integrate with single header file
  • Rich documentation and community support
  • Automatic serialization for custom types
  • Full UTF-8 support for internationalization
  • Active development and maintenance

Disadvantages

  • Performance lags behind other C++ JSON libraries
  • Large file size (approximately 1MB)
  • May increase compilation time
  • Requires C++11 or later
  • Relatively high memory usage
  • Not suitable for processing huge JSON files

References

Code Examples

Basic Usage

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

using json = nlohmann::json;

int main() {
    // Creating JSON object
    json j = {
        {"name", "John Doe"},
        {"age", 30},
        {"city", "Tokyo"},
        {"is_active", true},
        {"scores", {85, 90, 78}}
    };
    
    // Serialization (pretty print)
    std::cout << j.dump(4) << std::endl;
    
    // Element access
    std::string name = j["name"];
    int age = j["age"].get<int>();
    
    return 0;
}

Parsing and Error Handling

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

using json = nlohmann::json;

void parseJsonFile(const std::string& filename) {
    try {
        // Read from file
        std::ifstream file(filename);
        json j;
        file >> j;
        
        // Safe element access
        if (j.contains("users")) {
            for (auto& user : j["users"]) {
                std::cout << user.at("name") << std::endl;
            }
        }
    } catch (json::parse_error& e) {
        std::cerr << "Parse error: " << e.what() << std::endl;
    } catch (json::out_of_range& e) {
        std::cerr << "Key not found: " << e.what() << std::endl;
    }
}

Custom Type Serialization

#include <nlohmann/json.hpp>

struct Person {
    std::string name;
    int age;
    std::string email;
};

// Automatic serialization using macro
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Person, name, age, email)

int main() {
    // Using custom type
    Person p{"Alice", 25, "[email protected]"};
    
    // Automatically convert to JSON
    json j = p;
    std::cout << j.dump(2) << std::endl;
    
    // From JSON to custom type
    json j2 = {{"name", "Bob"}, {"age", 30}, {"email", "[email protected]"}};
    Person p2 = j2.get<Person>();
    
    return 0;
}

Advanced Features

#include <nlohmann/json.hpp>

using json = nlohmann::json;

void advancedFeatures() {
    json j = {
        {"users", {
            {{"name", "John"}, {"age", 30}},
            {{"name", "Jane"}, {"age", 25}}
        }}
    };
    
    // JSON pointer
    auto name = j[json::json_pointer("/users/0/name")];
    
    // JSON patch
    json patch = {{
        {"op", "replace"},
        {"path", "/users/0/age"},
        {"value", 31}
    }};
    j = j.patch(patch);
    
    // Iteration
    for (auto& [key, value] : j.items()) {
        std::cout << key << ": " << value << std::endl;
    }
    
    // MessagePack conversion
    std::vector<uint8_t> msgpack = json::to_msgpack(j);
    json j_from_msgpack = json::from_msgpack(msgpack);
}

SAX-style Parsing

#include <nlohmann/json.hpp>

class MySaxHandler {
public:
    bool null() { return true; }
    bool boolean(bool val) { return true; }
    bool number_integer(int64_t val) { return true; }
    bool number_unsigned(uint64_t val) { return true; }
    bool number_float(double val, const std::string& s) { return true; }
    bool string(std::string& val) { return true; }
    bool start_object(std::size_t elements) { return true; }
    bool end_object() { return true; }
    bool start_array(std::size_t elements) { return true; }
    bool end_array() { return true; }
    bool key(std::string& val) { return true; }
    bool parse_error(std::size_t position, const std::string& last_token) { return false; }
};

void saxParsing() {
    std::string json_str = R"({"name": "John", "age": 30})";
    MySaxHandler handler;
    json::sax_parse(json_str, &handler);
}

Configuration File Read/Write

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

class Config {
    json config_;
    std::string filename_;
    
public:
    Config(const std::string& filename) : filename_(filename) {
        load();
    }
    
    void load() {
        try {
            std::ifstream file(filename_);
            if (file.is_open()) {
                file >> config_;
            }
        } catch (...) {
            config_ = json::object();
        }
    }
    
    void save() {
        std::ofstream file(filename_);
        file << config_.dump(4);
    }
    
    template<typename T>
    T get(const std::string& key, const T& default_value) {
        return config_.value(key, default_value);
    }
    
    template<typename T>
    void set(const std::string& key, const T& value) {
        config_[key] = value;
    }
};