Month DD, 2026

bdljsn::Json Enchancements

Since Introducing bdljsn::Json many features have been added that make use of that component easier and more effective. The purpose of this article is summarize these features for our users.

Added Conversions and Fluent Operators

Recently added methods and implicit conversions allow users to compose and operate on Json objects with less code clutter.

Additionally, many manipulator methods that had previously returned void now return an reference to the object (a.k.a., a “fluent” method). Successive invocations of these manipulators can now be combined into a single expression.

Consider the assembly of an array-type Json object. Previously that would might look like this:

Json json;                                    // Create the `Json` object.
json.makeArray();                             // Make it an array type.
json.theArray().pushBack(Json(42));           // Must access via `theArray`.
json.theArray().pushBack(Json("string"));     // `pushBack` `Json` objects.
json.theArray().pushBack(Json(false));        // "                         "
json.theArray().pushBack(Json(JsonObject())); // "                         "
json.theArray().pushBack(Json(JsonNull()));   // "                         "

assert(json[0] == Json(42));           // Must compare `Json` objects.
assert(json[1] == Json("string"));     // "                          "
assert(json[2] == Json(false));        // "                          "
assert(json[3] == Json(JsonObject())); // "                          "
assert(json[4] == Json(JsonNull()));   // "                          "

Now, the same code can be written more concisely:

Json json;                   // Create the (null) `Json` object.
json.pushBack(42)            // We need not invoke `makeArray`
    .pushBack("string")      // We need not invoke `theArray`.
    .pushBack(false)         // Pushed values need not be `Json` objects.
    .pushBack(JsonObject())  // `pushBack` is "fluent" -- need not repeat
    .pushBack(JsonNull());   // the `json` variable name.

assert(json[0] == 42);           // Can compare `Json` objects
assert(json[1] == "string");     // to non-`Json` values.
assert(json[2] == false);
assert(json[3] == JsonObject());
assert(json[4] == jsonNull);     // Note: Use `JsonNull` constant.

Notice that the Json class now has many methods that mirror methods of of JsonArray (e.g., pushBack) so array operations can be performed directly on the Json object without using the theArray() method that was previously required. Moreover, when array operations are applied to a Json object having type JsonNull, that object’s type is implicitly converted to JsonArray.

Similarly, many of the methods of JsonObject have also been “imported” to Json and they too implicitly change a Json object’s type from JsonNull to JsonObject.

The bdljsn::jsonNull Constant

Notice in the final line of the previous example that bdljsn_jsonnull now defines, bdljsn::jsonNull (leading lower case j), a constant having the singular value of the bdljsn::JsonNull class.

Initializer List Enhancements

For some time, the bdljsn::JsonArray and bdljsn::JsonObect and classes have provided constuctors and maniuplator methods that accept std::initializer_list class templates. Thus, users have been able to define those objects using braced lists of Json objects to define JsonArray objects and braced lists of key/Json objects to to define JsonObject objects. For example:

JsonArray array0 {  // A list of `Json` objects
    Json(123),
    Json("string"),
    Json(true),
    Json(JsonObject())
};

JsonObject object0 { // A mapping from key values to `Json` objects.
    { "play", Json("Waiting for Godot") },
    { "characters", Json(JsonArray {
                            Json("Didi"),
                            Json("Gogo"),
                            Json("Pozzo"),
                            Json("Lucky")}
                        )
    }
};

More recently, the implementation has been generalized so those braced lists consist of a wide assortment type suitable for constructing Json objects. Thus, the previous example can now be written more concisely (and more readably):

JsonArray array1 {  // The list elements need no longer be `Json` objects.
    123,
    "string",
    true,
    JsonObject { }
};

JsonObject object1 { // The values need no longer be `Json` objects.
    { "play", "Waiting for Godot" },
    { "characters", JsonArray {
                        "Didi",
                        "Gogo",
                        "Pozzo",
                        "Lucky" }
    }
};

assert( array0 ==  array1);
assert(object0 == object1);

The types accepted in braced lists include:

  • bool

  • integral types

  • float

  • double

  • bdldfp::Decimal64

  • const char *

  • const bsl::string&

  • const std::string&

  • const std::pmr::string& (where available)

  • const bsl::string_view&

  • const std::string_view& (where distinct from bsl::string_view)

  • JsonNull

  • JsonNumber

  • JsonArray

  • JsonObject

  • Json

Finally, the bdljsn::Json class itself did not and still does not directly support initializer lists:

Json jx = { {"a", 1}, {"b", 2} };  // Error.  No such CTOR.

                                   // Note: User intent is ambiguous.
                                   //  * Object having two members, or
                                   //  * Array having two elements, each
                                   //    an array of two elements?

To disambiguate intent when creating a Json object from an std::initializer_list, qualify the statement by supplying the JsonArray/JsonObject types explicitly.

Json ja = JsonArray { {"a", 1}, {"b", 2} };

assert(true == ja.isArray());
assert(2    == ja.size());
assert(true == ja[0].isArray());
assert(true == ja[1].isArray());

Json jo = JsonObject{ {"a", 1}, {"b", 2} };

assert(true == jo.isObject());
assert(2    == jo.size());
assert(true == jo.contains("a"));
assert(1    == jo["a"]);
assert(true == jo.contains("b"));
assert(2    == jo["b"]);

The visit Method

The bdljsn::Json class now has the (overloaded) visit method which supports the “visitor” pattern. In this pattern, a user-supplied, type-based functor is invoked for each of the nodes of a JSON document. See bdljsn_json Example 3: Using the visit Method to Traverse a Json Object.