Type support

Predefined types

Standard library

These types are supported by this library:

  • Basic types: bool, char, int, unsigned int, long long, unsigned long long, std::string
  • Array types: std::vector<>, std::deque<>, std::array<>, std::tuple<> (this one needs special care)
  • Nullable types: std::nullptr_t, std::unique_ptr<>, std::shared_ptr<>
  • Map types: std::map<>, std::unordered_map<>, std::multimap<>, std::unordered_multimap<> (The key must be of string type)
  • Object types: any class generated by the script autojsoncxx.py.
  • DOM: rapidjson::Document

Notes:

  • char is mapped to JSON Boolean type, the same as bool.

Boost

If you include <autojsoncxx/boost_types.hpp> (a relatively new boost is required), you will also get support for

  • Array types: boost::container::vector<>, boost::container::deque<>, boost::array
  • Nullable types: boost::shared_ptr<>, boost::optional<>
  • Map types: boost::unordered_map<>, boost::unordered_multimap<> (The key must be of string type)

Caveat

No raw pointer and reference types are supported. Use smart pointers instead. They do not convey any information about ownership, and will make correct memory management (especially by a code generator) much more difficult.

Nested types

The supported types can be arbitrarily nested, for example

#define AUTOJSONCXX_MODERN_COMPILER 1 
#include <iostream>
#include "person.hpp"

int main()
{
    auto test = std::make_tuple(std::vector<std::string>{ "A", "BC", "DEF" }, nullptr,
                                3.1415926, -223, std::shared_ptr<int>(),
                                std::map<std::string, bool>{ { "a", true }, 
                                                           { "Δ", false } },
                                std::make_shared<std::array<Person, 2>>());

    std::string str;

    // This requires true variadic template support 
    // MSVC 2012 has std::tuple<>, but it is faked with macros
    // Avoid std::tuple<> if your compiler is not strong enough
    autojsoncxx::to_pretty_json_string(str, test);

    std::cout << str << '\n';
    return 0;
}

Sample output

[
    [
        "A",
        "BC",
        "DEF"
    ],
    null,
    3.1415926,
    -223,
    null,
    {
        "a": true,
        "Δ": false
    },
    [
        {
            "ID": 0,
            "name": "anonymous",
            "height": 0.0,
            "weight": 0.0,
            "known_associates": []
        },
        {
            "ID": 0,
            "name": "anonymous",
            "height": 0.0,
            "weight": 0.0,
            "known_associates": []
        }
    ]
]

Self defined type

The core of the library is two template class, SAXEventHandler and Serializer. The base templates are defined as:

namespace autojsoncxx {

// The core handlers for parsing
template <class T>
class SAXEventHandler;

// Only the second parameter should be specialized
template <class Writer, class T>
struct Serializer;

}

Each of the full or partial specialization of these templates will add new type support to the library.

Writing the handler is somewhat difficult, because there are a multitude of errors that can result from a mismatched JSON. So there is some base classes provided, based on Curiously Recurring Template Pattern. For primitive types, such as a simple variant of int and bool, or string types (QString, CString, icu::UnicodeString, YetAnotherStringThatIsSoMuchBetterThanTheRest), derive from BaseSAXEventHandler. There are also base classes for array type VectorBaseSAXEventHandler, nullable type NullableBaseSAXEventHandler, map type MapBaseSAXEventHandler. If you implement your own string, you probably want to add map type support as well, because the default implementation is specialized on std::string.

Writing the serializer is very easy, and one can easily figure it out by looking at the source code.

Special types

Tuple

There are only one tuple type supported std::tuple (boost::tuple is not supported). Implementing it requires true variadic templates. If you want to use it, you need to define both AUTOJSONCXX_HAS_MODERN_TYPES and AUTOJSONCXX_HAS_VARIADIC_TEMPLATE to be nonzero. The macro AUTOJSONCXX_MODERN_COMPILER automatically turns on both two.

The tuple type is mapped to a JSON array of heterogenous types. So std::tuple<int, std::string, double> maps to a JSON array of three element of type Number, String, and Number respectively.

During parsing, only the prefix is matched. That is, if the JSON array is longer than the tuple size, the extraneous part will be silently dropped; if the JSON array is shorter than the tuple size, the not-mapped element simply remains untouched. This design is based on the assumption that when you need a heterogeneous array, you probably prioritize flexibility over strict conformance.

DOM

rapidjson::Document is the only DOM type supported. The envisioned use is to freely intermix static and dynamic typing. That is, part of a C++ struct is converted according to strict rules, while other part are flexibly handled.

In addition, you can convert any supported type to/from a DOM object directly. The relevant functions are surprisingly named autojsoncxx::to_document and autojsoncxx::from_document.