Component of the Week #39: baljsn_simpleformatter

Summary:
  • Provides a simple formatter for encoding data in the JSON format.

Need to generate JSON output programmatically? Building a REST API response or creating configuration files? The baljsn_simpleformatter component provides baljsn::SimpleFormatter, a class that makes it easy to construct well-formed JSON documents with a clean, intuitive API.

Why “Simple”?

BDE already has baljsn::Formatter, a lower-level, stateless formatter. SimpleFormatter tracks state internally, so you don’t need to manually call openMember()/closeMember() or add array separators - it handles all the bookkeeping automatically. Compare:

// Using baljsn::Formatter
formatter.openObject();
formatter.openMember("name");
formatter.putValue("Alice");
formatter.closeMember();
formatter.openMember("age");
formatter.putValue(30);
// Must remember NOT to call closeMember here!
formatter.closeObject();

// Using baljsn::SimpleFormatter
formatter.openObject();
formatter.addValue("name", "Alice");
formatter.addValue("age", 30);
formatter.closeObject();

Formatting Options

By default, SimpleFormatter produces compact JSON. For human-readable output, enable pretty-printing with EncoderOptions:

baljsn::EncoderOptions options;
options.setEncodingStyle(baljsn::EncoderOptions::e_PRETTY);
options.setSpacesPerLevel(2);

baljsn::SimpleFormatter formatter(bsl::cout, options);

formatter.openObject();
formatter.addValue("name", "Bob");
formatter.addValue("age", 25);
formatter.closeObject();

// Output:
// {
//   "name": "Bob",
//   "age": 25
// }

Working with Arrays

Arrays work similarly - just open and close them. Array elements don’t have names:

baljsn::SimpleFormatter formatter(bsl::cout);

formatter.openArray();
formatter.addValue(1);
formatter.addValue(2);
formatter.addValue(3);
formatter.closeArray();

// Output: [1,2,3]

Nested Structures

Objects and arrays can be nested arbitrarily. Named fields use one overload, unnamed array elements use another:

baljsn::SimpleFormatter formatter(bsl::cout);

formatter.openObject();
formatter.addValue("name", "Alice");

// Named array inside object
formatter.openArray("scores");
formatter.addValue(95);
formatter.addValue(87);
formatter.addValue(92);
formatter.closeArray();

// Named nested object
formatter.openObject("address");
formatter.addValue("city", "New York");
formatter.addValue("zip", "10001");
formatter.closeObject();

formatter.closeObject();

// Output: {"name":"Alice","scores":[95,87,92],"address":{"city":"New York","zip":"10001"}}

Type Safety

SimpleFormatter uses templates for addValue(), so it works with any type that baljsn::PrintUtil knows how to format - strings, numbers, bools, and many BDE types like bdlt::Datetime, bdldfp::Decimal64, etc.

Comparison to Alternatives

  • vs. baljsn::Formatter: SimpleFormatter tracks state and handles formatting automatically, making it much easier to use. Formatter is stateless and gives you lower-level control - useful if you’re generating JSON incrementally across different functions or need precise control over output, but requires manual state management.

  • vs. bdljsn::Json: SimpleFormatter writes directly to a stream without building an in-memory DOM, making it more efficient for large documents.

  • vs. manual string concatenation: Proper escaping, type-safe, and guaranteed well-formed JSON.

For more information, check out the documentation for baljsn_simpleformatter.