


A cross-platform C++20 JSON extensible serialization library with type-safe manipulation, automatic serialization, and schema validation
Overview
nfx-serialization is a modern C++20 library providing comprehensive JSON serialization and deserialization capabilities. It offers type-safe document manipulation, automatic type mapping through an extensible trait system, STL-compatible iterators for arrays and objects, and JSON Schema validation - all optimized for performance across multiple platforms and compilers.
Key Features
📦 Core JSON Components
- Document: Generic JSON document abstraction with type-safe value access and manipulation
- Serializer: Template-based automatic serialization/deserialization with extensible trait customization
- SchemaValidator: JSON Schema Draft 2020-12 validation with detailed error reporting
- SchemaGenerator: Automatic JSON Schema generation from sample documents with format detection
🔄 Automatic Type Mapping
- POD types (integers, floats, booleans, strings)
- STL containers (vector, array, list, deque, set, unordered_set, map, unordered_map)
- Smart pointers (unique_ptr, shared_ptr)
- Optional types (std::optional, std::nullopt)
- Custom types via SerializationTraits specialization
- Nested structures and containers
✅ JSON Schema Validation
- JSON Schema Draft 2020-12 support
- Comprehensive constraint validation (type, required, properties, etc.)
- Detailed error reporting with JSON Pointer paths
- Custom error messages and validation contexts
📊 Real-World Applications
- Configuration management (app settings, environment configs)
- API request/response handling (REST, GraphQL)
- Data persistence and caching
- Inter-process communication (IPC)
- Log processing and analysis
- Database document storage (NoSQL, MongoDB-style)
- Game save states and player data
- Message queue payloads (Kafka, RabbitMQ)
⚡ Performance Optimized
- Zero-copy document navigation with JSON Pointers
- STL-compatible iterators for arrays and objects with range-for support
- Compile-time type detection and optimization
- Header-only template implementations
🌍 Cross-Platform Support
- Linux, Windows
- GCC 14+, Clang 18+, MSVC 2022+
- Thread-safe operations
- Consistent behavior across platforms
Quick Start
Requirements
- C++20 compatible compiler:
- GCC 14+ (14.2.0 tested)
- Clang 18+ (19.1.7 tested)
- MSVC 2022+ (19.44+ tested)
- CMake 3.20 or higher
CMake Integration
# --- JSON serialization support ---
option(NFX_SERIALIZATION_WITH_JSON "Enable JSON serialization support" ON )
# --- Library build types ---
option(NFX_SERIALIZATION_BUILD_STATIC "Build static library" OFF)
option(NFX_SERIALIZATION_BUILD_SHARED "Build shared library" OFF)
# --- Build components ---
option(NFX_SERIALIZATION_BUILD_TESTS "Build tests" OFF)
option(NFX_SERIALIZATION_BUILD_EXTENSION_TESTS "Build extension tests" OFF)
option(NFX_SERIALIZATION_BUILD_SAMPLES "Build samples" OFF)
option(NFX_SERIALIZATION_BUILD_BENCHMARKS "Build benchmarks" OFF)
option(NFX_SERIALIZATION_BUILD_DOCUMENTATION "Build Doxygen documentation" OFF)
# --- Installation ---
option(NFX_SERIALIZATION_INSTALL_PROJECT "Install project" OFF)
# --- Packaging ---
option(NFX_SERIALIZATION_PACKAGE_SOURCE "Enable source package generation" OFF)
option(NFX_SERIALIZATION_PACKAGE_ARCHIVE "Enable TGZ/ZIP package generation" OFF)
option(NFX_SERIALIZATION_PACKAGE_DEB "Enable DEB package generation" OFF)
option(NFX_SERIALIZATION_PACKAGE_RPM "Enable RPM package generation" OFF)
option(NFX_SERIALIZATION_PACKAGE_WIX "Enable WiX Windows installer (MSI)" OFF)
Using in Your Project
Option 1: Using FetchContent (Recommended)
include(FetchContent)
FetchContent_Declare(
nfx-serialization
GIT_REPOSITORY https://github.com/nfx-libs/nfx-serialization.git
GIT_TAG main # or use specific version tag like "0.1.0"
)
FetchContent_MakeAvailable(nfx-serialization)
# Link with static library
target_link_libraries(your_target PRIVATE nfx-serialization::static)
Option 2: As a Git Submodule
# Add as submodule
git submodule add https://github.com/nfx-libs/nfx-serialization.git third-party/nfx-serialization
# In your CMakeLists.txt
add_subdirectory(third-party/nfx-serialization)
target_link_libraries(your_target PRIVATE nfx-serialization::static)
Option 3: Using find_package (After Installation)
find_package(nfx-serialization REQUIRED)
target_link_libraries(your_target PRIVATE nfx-serialization::static)
Building
Build Commands:
# Clone the repository
git clone https://github.com/nfx-libs/nfx-serialization.git
cd nfx-serialization
# Create build directory
mkdir build && cd build
# Configure with CMake
cmake .. -DCMAKE_BUILD_TYPE=Release
# Build the library
cmake --build . --config Release --parallel
# Run tests (optional)
ctest -C Release --output-on-failure
# Run benchmarks (optional)
./bin/Release/BM_JSON_Serialization
Documentation
nfx-serialization includes API documentation generated with Doxygen.
📚 Online Documentation
The complete API documentation is available online at: https://nfx-libs.github.io/nfx-serialization
Building Documentation Locally
# Configure with documentation enabled
cmake .. -DCMAKE_BUILD_TYPE=Release -DNFX_SERIALIZATION_BUILD_DOCUMENTATION=ON
# Build the documentation
cmake --build . --target nfx-serialization-documentation
Requirements
- Doxygen - Documentation generation tool
- Graphviz Dot (optional) - For generating class diagrams
Accessing Local Documentation
After building, open ./build/doc/html/index.html in your web browser.
Usage Examples
Document - JSON Manipulation
using namespace nfx::serialization::json;
doc.
set<std::string>(
"/name",
"John Doe");
doc.
set<
int>(
"/age", 30);
doc.
set<std::string>(
"/email",
"john.doe@example.com");
auto name = doc.
get<std::string>(
"/name");
auto age = doc.
get<
int>(
"/age");
doc.
set<std::string>(
"/address/city",
"New York");
doc.
set<std::string>(
"/address/zip",
"10001");
doc.
set<std::string>(
"/hobbies/0",
"reading");
doc.
set<std::string>(
"/hobbies/1",
"gaming");
doc.
set<std::string>(
"/hobbies/2",
"coding");
Generic document abstraction for JSON serialization.
Generic JSON document abstraction for serialization.
void set(std::string_view path, const T &value)
Set typed value at specified path (copy version).
std::optional< T > get(std::string_view path) const
Get typed value at specified path.
std::string toString(int indent=0) const
Convert document to JSON string.
Serializer - Automatic Type Mapping
#include <vector>
#include <map>
using namespace nfx::serialization::json;
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::map<std::string, int> scores = { {"Alice", 95}, {"Bob", 87} };
opts.prettyPrint = true;
Templated JSON serializer with compile-time type mapping.
Templated JSON serializer with compile-time type mapping.
Array Iteration with Range-For
using namespace nfx::serialization::json;
"items": [
{"id": 1, "name": "Item A"},
{"id": 2, "name": "Item B"},
{"id": 3, "name": "Item C"}
]
})");
if (!docOpt)
{
return 1;
}
if (itemsOpt)
{
for (const auto& item : itemsOpt.value())
{
auto id = item.get<int64_t>("id");
auto name = item.get<std::string>("name");
if (id && name)
{
std::cout << "ID: " << *id << ", Name: " << *name << std::endl;
}
}
}
static std::optional< Document > fromString(std::string_view jsonStr)
Create document from JSON string.
JSON array wrapper for Document.
Object Iteration with Range-For
using namespace nfx::serialization::json;
"config": {
"timeout": 30,
"retries": 3,
"debug": true
}
})");
if (!docOpt)
{
return 1;
}
if (configOpt)
{
for (const auto& [key, value] : configOpt.value())
{
std::cout << "Key: " << key << ", Value: " << value.toString() << std::endl;
}
}
JSON object wrapper for Document.
SchemaValidator - JSON Schema Validation
using namespace nfx::serialization::json;
"type": "object",
"required": ["name", "age"],
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0, "maximum": 150},
"email": {"type": "string", "format": "email"}
}
})");
if (!schemaOpt)
{
std::cerr << "Invalid schema JSON" << std::endl;
return 1;
}
if (!dataOpt) {
std::cerr << "Invalid data JSON" << std::endl;
return 1;
}
{
std::cout << "Document is valid!" << std::endl;
}
else
{
std::cout << "Validation errors:" << std::endl;
for (
const auto& error : result.
errors())
{
std::cout << " - " << error.toString() << std::endl;
}
}
JSON Schema validation for Document instances.
Result of JSON schema validation operation.
const std::vector< ValidationError > & errors() const noexcept
Get all validation errors.
bool isValid() const noexcept
Check if validation was successful.
JSON Schema validator for Document instances.
SchemaGenerator - Automatic Schema Generation
using namespace nfx::serialization::json;
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"tags": ["developer", "manager"],
"address": {
"city": "New York",
"zip": "10001"
}
})");
if (!dataOpt)
{
std::cerr << "Invalid data JSON" << std::endl;
return 1;
}
opts.
title =
"User Schema";
const Document& schema = generator.schema();
std::cout << schema.
toString(2) << std::endl;
JSON Schema generation from Document instances.
JSON Schema generator from Document instances.
Configuration options for schema generation.
bool inferFormats
Detect string formats (email, date, URI, UUID, etc.).
std::string description
Schema description (optional).
std::string title
Schema title (optional).
Sample Output:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "User Schema",
"description": "Generated from sample data",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"email": {
"type": "string",
"format": "email"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"address": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"zip": {
"type": "string"
}
},
"required": ["city", "zip"]
}
},
"required": ["name", "age", "email", "tags", "address"]
}
Complete Example
#include <iostream>
#include <vector>
int main()
{
using namespace nfx::serialization::json;
doc.
set<std::string>(
"/title",
"My Application" );
doc.
set<std::string>(
"/version",
"1.0.0" );
std::vector<std::string> users = { "Alice", "Bob", "Charlie" };
if ( usersDoc )
{
}
doc.
set<
bool>(
"/config/debug", true );
doc.
set<
int>(
"/config/timeout", 30 );
std::cout << "Generated JSON:\n"
<< json << std::endl;
if ( usersArrayOpt )
{
std::cout << "\nUsers:" << std::endl;
for ( const auto& userDoc : usersArrayOpt.value() )
{
auto user = userDoc.get<std::string>( "" );
if ( user )
{
std::cout << " - " << *user << std::endl;
}
}
}
if ( usersDocOpt )
{
std::string usersArrayJson = usersDocOpt->toString();
std::cout << "\nRestored " << restored.size() << " users" << std::endl;
}
return 0;
}
Sample Output:
Generated JSON:
{
"title": "My Application",
"version": "1.0.0",
"users": [
"Alice",
"Bob",
"Charlie"
],
"config": {
"debug": true,
"timeout": 30
}
}
Users:
- Alice
- Bob
- Charlie
Restored 3 users
Custom Traits - Extending for Your Types
The serializer can work with your custom container types and user-defined structures through a simple trait system. There are two main approaches:
Approach 1: Mark Custom Containers (Trait Specialization)
If you have a custom container that implements a standard container interface (iterators, typedefs, insert/operator[]), you can mark it as a container so the Serializer treats it like STL containers:
template<typename K, typename V>
struct CustomHashMap {
using key_type = K;
using mapped_type = V;
using value_type = std::pair<const K, V>;
V& operator[](const K& key);
auto begin() -> ;
auto end() -> ;
};
template<typename T>
struct CustomSet {
using value_type = T;
void insert(const T& value);
auto begin() -> ;
auto end() -> ;
};
namespace nfx::serialization::json::detail {
template<typename K, typename V>
struct is_container<CustomHashMap<K,V>> : std::true_type {};
template<typename T>
struct is_container<CustomSet<T>> : std::true_type {};
}
CustomHashMap<std::string, int> myMap;
myMap["answer"] = 42;
Container Interface Requirements:
For sequence containers (vector, list, set):
- using value_type = T;
- begin() / end() returning iterators
- insert(const value_type&) for deserialization
For associative containers (map, unordered_map):
- using key_type = K;
- using mapped_type = V;
- using value_type = std::pair<const K, V>;
- operator[](const key_type&) for deserialization
- begin() / end() returning iterators
Approach 2: Custom Serialization Logic (SerializationTraits)
For types that need special handling or don't fit the container model, implement SerializationTraits:
struct Point3D {
double x, y, z;
};
template<>
static void serialize(
const Point3D& point,
Document& doc) {
doc.
set<
double>(
"/x", point.x);
doc.
set<
double>(
"/y", point.y);
doc.
set<
double>(
"/z", point.z);
}
static void deserialize(Point3D& point,
const Document& doc) {
point.x = doc.
get<
double>(
"/x").value_or(0.0);
point.y = doc.
get<
double>(
"/y").value_or(0.0);
point.z = doc.
get<
double>(
"/z").value_or(0.0);
}
};
Point3D origin{0, 0, 0};
static std::string toString(const T &obj, const Options &options={})
Serialize object to JSON string.
Default serialization traits - users can specialize this.
static void deserialize(T &obj, const Document &doc)
Default deserialize implementation - delegates to member method.
Key Points:
- Container trait specializations go in nfx::serialization::json::detail namespace
- SerializationTraits specializations go in nfx::serialization::json namespace
- You don't modify library code - just expose the minimal interface
- Mix both approaches: use trait marking for containers, SerializationTraits for custom logic
- See samples/Sample_JsonSerializer.cpp for complete working examples
Optional Extensions
nfx-serialization provides optional integration headers for other nfx libraries. These headers use conditional compilation (__has_include()) and are safe to include even if the external library is not installed:
Available Extensions
- extensions/ContainersTraits.h - Serialization support for nfx-containers types
- nfx::containers::PerfectHashMap - Compile-time perfect hash map
- nfx::containers::FastHashMap - Runtime open-addressing hash map
- nfx::containers::FastHashSet - Runtime open-addressing hash set
- extensions/DatatypesTraits.h - Serialization support for nfx-datatypes types
- nfx::datatypes::Int128 - 128-bit integer (cross-platform)
- nfx::datatypes::Decimal - Fixed-point decimal arithmetic
- extensions/DateTimeTraits.h - Serialization support for nfx-datetime types
- nfx::time::DateTime - Date and time representation (ISO 8601)
- nfx::time::DateTimeOffset - Date and time with timezone offset
- nfx::time::TimeSpan - Duration/time interval
Usage
#include <nfx/containers/FastHashMap.h>
#include <nfx/datetime/DateTime.h>
using namespace nfx::serialization::json;
nfx::containers::FastHashMap<std::string, int> scores;
scores.insertOrAssign("Alice", 95);
scores.insertOrAssign("Bob", 87);
std::string json =
Serializer<
decltype(scores)>::toString(scores);
nfx::time::DateTime now = nfx::time::DateTime::now();
SerializationTraits specializations for nfx-containers types.
SerializationTraits specializations for nfx-datetime types.
Note: These extensions are header-only and zero-cost - if you don't include them or don't have the external library installed, they have no impact on compile time or binary size.
Installation & Packaging
nfx-serialization provides packaging options for distribution.
Package Generation
# Configure with packaging options
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DNFX_SERIALIZATION_BUILD_STATIC=ON \
-DNFX_SERIALIZATION_BUILD_SHARED=ON \
-DNFX_SERIALIZATION_PACKAGE_ARCHIVE=ON \
-DNFX_SERIALIZATION_PACKAGE_DEB=ON \
-DNFX_SERIALIZATION_PACKAGE_RPM=ON
# Generate binary packages
cmake --build . --target package
# or
cd build && cpack
# Generate source packages
cd build && cpack --config CPackSourceConfig.cmake
Supported Package Formats
| Format | Platform | Description | Requirements |
| TGZ/ZIP | Cross-platform | Compressed archive packages | None |
| DEB | Debian/Ubuntu | Native Debian packages | dpkg-dev |
| RPM | RedHat/SUSE | Native RPM packages | rpm-build |
| WiX | Windows | Professional MSI installer | WiX 3.11+ |
| Source | Cross-platform | Source code distribution (TGZ+ZIP) | None |
Installation
# Linux (DEB-based systems)
sudo dpkg -i nfx-serialization_*_amd64.deb
# Linux (RPM-based systems)
sudo rpm -ivh nfx-serialization-*-Linux.rpm
# Windows (MSI installer)
nfx-serialization-0.1.0-MSVC.msi
# Manual installation (extract archive)
tar -xzf nfx-serialization-*-Linux.tar.gz -C /usr/local/
Project Structure
nfx-serialization/
├── benchmark/ # Performance benchmarks with Google Benchmark
├── cmake/ # CMake modules and configuration
├── include/nfx/ # Public headers: Document, Serializer, SchemaValidator
├── samples/ # Example usage and demonstrations
├── src/ # Implementation files
└── test/ # Comprehensive unit tests with GoogleTest
Performance
For detailed performance metrics and benchmarks, see the benchmark documentation.
Roadmap
See TODO.md for upcoming features and project roadmap.
Changelog
See the CHANGELOG.md for a detailed history of changes, new features, and bug fixes.
License
This project is licensed under the MIT License.
Dependencies
- nfx-stringutils: String validation utilities (MIT License) - Core dependency
- nlohmann/json: Modern JSON library for C++ (MIT License) - Core dependency
Development Dependencies
- GoogleTest: Testing framework (BSD 3-Clause License) - Development only
- Google Benchmark: Performance benchmarking framework (Apache 2.0 License) - Development only
All dependencies are automatically fetched via CMake FetchContent when building the library, tests, or benchmarks.
Updated on December 20, 2025