CJM v0.5.1

Build-time Metadata Compiler for Modern C++

Metadata compiler for Modern C++.

Write ordinary C++ models without repeating every same-name JSON tag. CJM now defaults managed fields to their exact C++ names, builds stable Metadata IR, and emits C++ integration plus JSON Schema artifacts during your build.

Explicit JSON metadata remains for exceptions: rename a field, add omitempty, or mark a field ignored. CJM is not a JSON library, schema-first generator, OpenAPI framework, or runtime validator.

Standard C++ in. Standard C++ out. Developers keep C++ models as the source of truth while CJM handles the repetitive integration code.

C++ Metadata IR Default mapping JSON Schema Build-time
user.hpp C++ Frontend
stable contract Metadata IR
backends nlohmann/json + Schema
user.hpp
enum class Status { Active, Disabled };

struct User {
    std::string name;
    Status status;
    std::optional<std::string> nickname; // json:",omitempty"
    std::string display_name;            // json:"displayName"
    int internal_id;                     // json:"-"
};

cjm generate \
  --input user.hpp \
  --output user.cjm.hpp

cjm generate-schema \
  --input user.hpp \
  --output user.schema.json
Input Standard C++
Workflow Stable Metadata IR
Backend nlohmann/json + JSON Schema
Runtime Zero overhead introduced by CJM

Focused early-adopter round

Early Adopters Welcome

CJM v0.5.1 is ready for early adopters who want build-time JSON integration, default field mapping, and JSON Schema artifacts from ordinary Modern C++ models.

The v0.4 public workflow has been dogfooded in a real downstream CMake project through FetchContent + cjm_generate. v0.5.0 added opt-in JSON Schema generation, and v0.5.1 makes same-name JSON field tags optional.

Try it on a practical model. If something fails or feels awkward, share the smallest header, the build command, and whether schema output was involved. CJM remains a documented practical subset, not production-stable v1.0 and not a full C++ parser.

Validated downstream workflow

FetchContent FetchContent_MakeAvailable cjm_generate(...) generated *.cjm.hpp optional generated schemas normal C++ test target

CJM's v0.4 public workflow was validated in ull-md-engine through the downstream CMake path documented on main.

The downstream coverage includes optionals, vectors, fixed-size arrays, ordered and unordered string-keyed maps, nested generated structs, enums, ignored fields, omitempty, fixed-width integers, enum string output, generated model-contract metadata, and generated to_json / from_json round trips.

Downstream quickstart

Use CJM Today

CJM v0.5.1 can be tried from a downstream CMake project with FetchContent. Packaged installation is future work, but the current release already supports the public cjm_generate workflow, default field mapping, and opt-in JSON Schema generation.

1

Write ordinary C++

#pragma once

#include <optional>
#include <string>

struct User {
    std::string name;
    int age = 0;
    std::optional<std::string> nickname; // json:",omitempty"
};
2

Add CJM with FetchContent

include(FetchContent)

FetchContent_Declare(
  cxx_json_codegen
  GIT_REPOSITORY https://github.com/cjm-labs/cxx-json-codegen.git
  GIT_TAG v0.5.1
)

FetchContent_MakeAvailable(cxx_json_codegen)

add_executable(app main.cpp)
target_link_libraries(app PRIVATE nlohmann_json::nlohmann_json)
3

Generate code and schemas

cjm_generate(
  TARGET app
  HEADERS user.hpp
  GENERATED_TARGET app_cjm_generated
  GENERATE_SCHEMAS
  GENERATED_SCHEMAS_VAR app_cjm_schemas
)

Schema generation is opt-in. CJM keeps C++ headers under generated/cjm and schema artifacts under generated/schemas.

4

Include generated code

#include "user.hpp"
#include "user.cjm.hpp"

#include <nlohmann/json.hpp>

nlohmann::json json = user;
User round_trip = json.get<User>();

Include the original model header first, then the generated *.cjm.hpp header. The generated backend code provides ordinary to_json / from_json integration for nlohmann/json.

v0.5.1 notes

  • Same-name fields default to exact C++ field names; no case conversion is applied.
  • Use json:"displayName" for explicit renames, json:",omitempty" for default-name omission, and json:"-" to ignore a field.
  • Use cjm generate-schema to emit a JSON Schema artifact from a supported header.
  • Use GENERATE_SCHEMAS to opt into schema generation from cjm_generate(...).
  • Pass every related model header explicitly; CJM does not automatically discover #include dependencies yet.
  • Generated schema files are build artifacts, not C++ sources and not include-path entries.
  • Schema output is generated from validated Metadata IR, not from a separate schema-first model.

Why CJM exists

Modern C++ is powerful. Everyday boilerplate should not be the cost.

Practical schema-shaped models often need repetitive glue for JSON integration, configuration, and metadata-aware workflows.

CJM removes that repetition without replacing C++, adding runtime reflection, or asking teams to adopt a new framework.

Architecture

Compiler architecture, normal compiler workflow.

CJM sits inside the build. The parser/frontend extracts source facts, semantic analysis builds Metadata IR, and backends consume that IR to generate ordinary C++ integration code and JSON Schema artifacts.

v0.5.1 current pipeline

C++ frontend
Metadata IR
nlohmann/json + JSON Schema backends

Long-term architecture

Source-language frontend
Language-neutral Metadata IR
Code-generation backend

What CJM does

CJM turns ordinary C++ declarations into a stable Metadata IR, then emits ordinary C++ code and JSON Schema artifacts for supported models.

  • Extracts field identity and source-level metadata from ordinary C++ declarations
  • Runs richer semantic analysis for practical model mapping
  • Defaults same-name JSON fields to exact C++ field names
  • Generates nlohmann/json integration code
  • Generates JSON Schema Draft 2020-12 artifacts from Metadata IR
  • Supports opt-in schema generation through CLI and CMake
  • Keeps generated outputs inspectable build artifacts

CJM v0.5.1 — Default Field Mapping

CJM v0.5.1 makes the normal model-authoring path less repetitive. Untagged managed fields use exact C++ names, while explicit metadata still handles renames, omitempty, and ignored fields.

default field mapping json:",omitempty" json:"-" ignored semantics duplicate effective-name diagnostics schema + contract alignment 30/30 tests passed
Read the v0.5.1 release notes

Supported v0.5.1 scope

nlohmann/json C++ integration JSON Schema Draft 2020-12 backend explicit CMake header registration one or more explicit input headers untagged fields use exact C++ field names explicit rename tags override defaults json:",omitempty" json:"-" preserved as ignored semantics duplicate effective JSON names diagnosed object schemas for generated structs scalar and string schema mappings fixed-width integer mappings std::array<T, N> schema extent std::map<std::string, T> std::unordered_map<std::string, T> std::vector<T> std::optional<T> enum and enum class string enums direct generated structs through $ref and $defs non-optional supported fields in required generated model-contract metadata

Verification

v0.5.1 verifies normalized field semantics and existing generated artifacts through the same parser/frontend -> semantic analysis -> Metadata IR pipeline.

default mapping semantic tests duplicate-name diagnostic tests schema backend golden tests CLI schema generation tests CMake schema artifact tests existing nlohmann backend tests contract backend tests parser and semantic tests generated-code compile tests basic example build/run tests 30/30 tests passed

Known limitations

v0.5.1 does not add a new runtime backend. It keeps nlohmann/json as the compatibility backend and strengthens the shared Metadata IR semantics used by schema and contract outputs.

automatic snake_case or camelCase conversion type-level opt-in metadata syntax schema output for nested containers schema containers whose element or value type is optional, enum, generated struct, or another container schema std::optional<T> for enum, generated struct, or container default-value metadata OpenAPI route generation HTTP endpoint policy runtime JSON Schema validation arbitrary JSON values std::variant / std::any pointer or polymorphic serialization custom converters custom enum string mapping policies time and datetime schema formats automatic header discovery full C++ grammar support at the CJM product level multiline managed field declarations private fields native JSON backend simdjson, Glaze, or yyjson runtime backends install/package distribution

Principles

Engineering before magic: CJM should remain early but architecture-driven, useful for practical schema-shaped C++ JSON models, and easy to inspect.

Ordinary C++ should be enough

Users write standard C++. Generated output is standard C++. Everything in between is CJM's responsibility.

Build-time instead of runtime

No hidden runtime, no dynamic reflection engine, and no runtime cost introduced by CJM.

Visible and predictable

Generated C++ should be readable, inspectable, and debuggable when developers need to look inside.

Native to existing builds

Adding CJM should feel like enabling another compiler tool inside an existing CMake project.

Long-term vision

Code generation should feel like the build simply got smarter.

v0.5.1 generates nlohmann/json integration and JSON Schema artifacts from normalized Metadata IR. The larger goal is a reusable compiler foundation for modern build-time metadata workflows in C++: simple user experience, production-quality engineering, and zero runtime overhead introduced by CJM.

CJM succeeds when developers forget that code generation is happening. They write standard C++, run their normal build, and everything works.