Write ordinary C++
#pragma once
#include <optional>
#include <string>
struct User {
std::string name;
int age = 0;
std::optional<std::string> nickname; // json:",omitempty"
};
CJM v0.5.2
Build-time Metadata Compiler for Modern C++
Write ordinary C++ models and generate recursive JSON Schema artifacts from the same normalized Metadata IR that drives C++ integration. CJM v0.5.2 also lays the documented runtime-semantics foundation for future high-performance JSON backends.
Same-name fields still default to exact C++ names, while explicit
JSON metadata remains for renames,
omitempty, and ignored fields. 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.
enum class Status { Active, Disabled };
struct Address {
std::string city;
};
struct User {
std::string name;
std::vector<Address> addresses;
std::optional<Status> status; // json:",omitempty"
};
cjm generate \
--input user.hpp \
--output user.cjm.hpp
cjm generate-schema \
--input user.hpp \
--output user.schema.json
Focused early-adopter round
CJM v0.5.2 is ready for early adopters who want build-time JSON integration, default field mapping, recursive JSON Schema artifacts, and documented runtime semantics for 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, v0.5.1 made same-name
JSON field tags optional, and v0.5.2 expands schema coverage over
recursive Metadata IR type shapes.
Try it on a practical model. If something fails or feels awkward, share the smallest header, the build command, and whether schema output or multiline declarations were involved. CJM remains a documented practical subset, not production-stable v1.0 and not a full C++ parser.
cjm_generate(...)
generated *.cjm.hpp
recursive 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
CJM v0.5.2 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 recursive opt-in JSON Schema generation.
#pragma once
#include <optional>
#include <string>
struct User {
std::string name;
int age = 0;
std::optional<std::string> nickname; // json:",omitempty"
};
include(FetchContent)
FetchContent_Declare(
cxx_json_codegen
GIT_REPOSITORY https://github.com/cjm-labs/cxx-json-codegen.git
GIT_TAG v0.5.2
)
FetchContent_MakeAvailable(cxx_json_codegen)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE nlohmann_json::nlohmann_json)
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.
#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.
json:"displayName" for explicit renames, json:",omitempty" for default-name omission, and json:"-" to ignore a field.cjm generate-schema to emit a JSON Schema artifact from a supported header.GENERATE_SCHEMAS to opt into schema generation from cjm_generate(...).#include dependencies yet.Why CJM exists
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
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.2 current pipeline
Long-term architecture
CJM turns ordinary C++ declarations into a stable Metadata IR, then emits ordinary C++ code and JSON Schema artifacts for supported models.
CJM v0.5.2 extends JSON Schema generation across recursive Metadata IR type shapes and adds the design/test foundation for future static runtime backend selection.
schema(T)
anyOf optional schemas
schema + contract + nlohmann closure
runtime semantic profile
static backend selection design
32/32 tests passed
json:",omitempty"
json:"-" preserved as ignored semantics
duplicate effective JSON names diagnosed
supported multiline field declarations
object schemas for generated structs
scalar and string schema mappings
fixed-width integer mappings
recursive std::array<T, N> schemas
std::map<std::string, T>
std::unordered_map<std::string, T>
recursive std::vector<T> schemas
std::optional<T> via anyOf + null
enum fields nested inside supported containers
generated structs nested inside supported containers
non-optional supported fields in required
generated model-contract metadata
runtime semantic profile docs
decode error and path model docs
runtime conformance fixture skeleton
v0.5.2 verifies recursive schema generation, recursive generated artifact closure, multiline frontend support, and the runtime foundation through the same parser/frontend -> semantic analysis -> Metadata IR pipeline.
v0.5.2 still does not add a new runtime backend. It keeps nlohmann/json as the compatibility backend while documenting the semantics future runtime backends must obey.
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
private fields
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.
Users write standard C++. Generated output is standard C++. Everything in between is CJM's responsibility.
No hidden runtime, no dynamic reflection engine, and no runtime cost introduced by CJM.
Generated C++ should be readable, inspectable, and debuggable when developers need to look inside.
Adding CJM should feel like enabling another compiler tool inside an existing CMake project.
Long-term vision
v0.5.2 generates nlohmann/json integration and recursive 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.
FAQ
CJM is a build-time metadata compiler for Modern C++. It reads
ordinary model declarations, builds Metadata IR, and generates
backend artifacts such as nlohmann/json integration and
JSON Schema.
No. The current official runtime integration backend targets
nlohmann/json. CJM generates model-specific integration
code around your C++ models.
v0.5.2 adds recursive JSON Schema fragments for supported Metadata IR type shapes and documents runtime semantics, decode error shape, conformance fixtures, and static backend selection for future backend work.