Component of the Week #29: bdljsn_json
- Summary:
A value-semantic type providing an in-memory representation of a JSON document, maintaining the invariant that all objects represent valid JSON.
The bdljsn::Json
component provides a complete in-memory representation of a JSON document. The
design closely mirrors the JSON grammar itself, supporting all JSON types:
objects, arrays, strings, numbers, booleans, and null values. The key design
principle is that every bdljsn::Json object represents a valid JSON
document - there is no “invalid” state.
bdljsn::Json is a very rich data structure with a lot of functionality. It would not be possible to cover everything in a short article. For more detail, please see the article Introducing bdljsn::Json, or see the component documentation.
In summary, the component provides three main classes:
bdljsn::Json- The main variant type representing any JSON valuebdljsn::JsonObject- Represents JSON objects (key-value maps)bdljsn::JsonArray- Represents JSON arrays (ordered sequences)
Additionally, bdljsn::JsonNumber encapsulates JSON numbers, preserving their
exact textual representation for precision. These numbers can then be converted
to various numeric types as needed.
Basic JSON Document Creation
Creating JSON documents is straightforward:
#include <bdljsn_json.h>
#include <bdldfp_decimal.h>
#include <bsl_iostream.h>
#include <assert.h>
using namespace BloombergLP;
using namespace bdldfp::DecimalLiterals;
int main()
{
bdljsn::Json json;
// Create a JSON object: {"name": "Alice", "age": 30, "active": true}
json.makeObject();
json["name"] = "Alice";
json["age"] = 30;
json["active"] = true;
// Access values with type checking
assert(json["name"].isString());
assert(json["name"].theString() == "Alice");
assert(json["age"].theNumber() == bdljsn::JsonNumber(30));
assert(json["active"].theBoolean() == true);
// Print the JSON structure
bsl::cout << json << bsl::endl;
return 0;
}
Reading and Writing JSON Text with bdljsn_jsonutil
While bdljsn::Json provides the in-memory representation, bdljsn_jsonutil
handles parsing JSON text and writing JSON objects back to text format:
#include <bdljsn_json.h>
#include <bdljsn_jsonutil.h>
#include <bsl_iostream.h>
#include <bsl_sstream.h>
#include <bsl_string.h>
#include <assert.h>
using namespace BloombergLP;
int main()
{
// JSON text to parse
const char *jsonText = R"({
"user": {
"name": "Bob",
"age": 25,
"preferences": ["coffee", "books", "coding"]
},
"timestamp": "2025-09-01T10:30:00Z",
"active": true
})";
// Parse JSON text into bdljsn::Json object
bdljsn::Json json;
bdljsn::Error error;
int rc = bdljsn::JsonUtil::read(&json, &error, jsonText);
if (0 != rc) {
bsl::cout << "Parse error: " << error << bsl::endl;
return 1;
}
// Access parsed data
assert(json["user"]["name"].theString() == "Bob");
assert(json["user"]["age"].theNumber() == bdljsn::JsonNumber(25));
assert(json["user"]["preferences"].theArray().size() == 3);
assert(json["active"].theBoolean() == true);
return 0;
}
Convenient JSON Literals
For even more concise JSON creation, bdljsn_jsonliterals provides user-defined
literals that parse JSON text directly into bdljsn::Json objects:
#include <bdljsn_json.h>
#include <bdljsn_jsonliterals.h>
#include <bsl_iostream.h>
#include <assert.h>
using namespace BloombergLP;
using namespace bdljsn::JsonLiterals; // Enable _json suffix
int main()
{
// Create JSON objects directly using (string) literals.
bdljsn::Json config = R"({
"server": {
"host": "localhost",
"port": 8080,
"ssl": true
},
"database": {
"type": "postgresql",
"connections": 10
},
"features": ["auth", "logging", "metrics"]
})"_json;
// Access the parsed data
assert(config["server"]["port"].theNumber() == bdljsn::JsonNumber(8080));
assert(config["server"]["ssl"].theBoolean() == true);
assert(config["features"].theArray().size() == 3);
// Literals work with simple values too
bdljsn::Json simpleArray = "[1, 2, 3, \"hello\"]"_json;
bdljsn::Json number = "42.5"_json;
bdljsn::Json boolean = "true"_json;
return 0;
}
Key Features and Design Principles
bdljsn::Json has several important characteristics:
Always Valid: Every
bdljsn::Jsonobject represents a valid JSON documentPrecise Numbers:
JsonNumberpreserves the exact textual representation, which can be converted to various numeric types, likeint,double, orbdldfp::Decimal64UTF-8 Strings: All string values are UTF-8
Standard Interface: Similar to STL containers with iterators, size(), etc.
The component pairs naturally with bdljsn_jsonutil for reading and writing
JSON text, making it easy to work with JSON data in network protocols,
configuration files, and APIs.
For more details and advanced usage, see: