DAW JSON Link
Classes

Arbitrary C++ data structures are supported and can be described using the trait json_data_contract.

Basic class mapping

Below is an ordinary JSON object

{
"member0": "this is a test",
"member1": 314159,
"member2": true
}

The above JSON describes a class with three members, a string named member0, an integer named member1, and a boolean named member2

Below is the C++ data structure and the trait to map the members to that of the JSON object. Note that the names of the C++ data members do not have to be the same as the JSON object's. To see a working example using this code, refer to cookbook_class1_test.cpp

{c++}
struct MyClass1 {
std::string member_0;
int member_1;
bool member_2;
};
namespace daw::json {
template<>
struct json_data_contract<MyClass1> {
using type = json_member_list<
json_string<"member0">,
json_number<"member1", int>,
json_bool<"member2">
>;
static inline auto to_json_data( MyClass1 const &value ) {
return std::forward_as_tuple(
value.member_0,
value.member_1,
value.member_2 );
}
};
}

The above json_data_contract trait maps the JSON members to the constructor of MyClass1 in the order specified. The arguments of type std::string, int, bool will be passed.

Class as a member

The serializing and deserializing is recursive. So if a class contains another class, the requirement is that that class has been mapped already. Assuming we already have the mapping above, lets embed that into another class

{
"a": {
"member0": "this is a test",
"member1": 314159,
"member2": true
},
"b": 1234
}

The JSON object that has a member "a" that matches MyClass1, and a second member is an unsigned To see a working example using this code, refer to cookbook_class2_test.cpp

{c++}
// Code from previous MyClass1 example
struct MyClass2 {
MyClass1 a;
unsigned b;
};
namespace daw::json {
template<>
struct json_data_contract<MyClass2> {
using type = json_member_list<
json_class<"a", MyClass1>,
json_number<"b", unsigned>
>;
static inline auto
to_json_data( MyClass2 const &value ) {
return std::forward_as_tuple( value.a, value.b );
}
};
} // namespace daw::json

Selective mapping

Not all the JSON objects members need to be mapped. Below is the same JSON object as in the MyClass2 example above. To see a working example using this code, refer to cookbook_class3_test.cpp

{
"a": {
"member0": "this is a test",
"member1": 314159,
"member2": true
},
"b": 1234
}
{c++}
// Code from previous MyClass1 example
struct MyClass3 {
MyClass1 a;
};
namespace daw::json {
template<>
struct json_data_contract<MyClass3> {
using type = json_member_list<json_class<"a", MyClass1>>;
static inline auto
to_json_data( MyClass3 const &value ) {
return std::forward_as_tuple( value.a );
}
};
}

Only the "a" member is mapped, the "b" member of the JSON object is ignored.

Alternate Class Mappings

If a type is already mapped or has many possible JSON mappings you can provide an alternate mapping. This is accomplished by mapping to the daw::json::json_alt<Type, Index> type. The optional index allows for any number of mappings that fit into a std::size_t.

To see a working example using this code, refer to cookbook_class_alternate1_test.cpp

{c++}
struct Thing {
int a;
};
namespace daw::json {
template<>
struct json_data_contract<Thing> {
using type = json_member_list<json_number<"a", int>>;
};
struct json_data_contract<json_alt<Thing>> {
using type = json_ordered_member_list<int>;
};
}
//...
Thing a = daw::json::from_json<Thing>( json_string_a );
Thing b = daw::json::from_json<daw::json::json_alt<Thing>>( json_string_b );

Class construction

If constructing the class requires extra steps than passing the parsed members to it's constructor one can provide a custom Constructor callable as the default for that type or for a specific json_class mapping.

Specifying the classes default

If one wants to change the default Constructor type of a specific type they can add a type alias in that classes json_data_contract. For instance, if a member needs extra checking that the types constructor does not provide:

struct FooConstructor {
constexpr Foo operator( )( std::string name, .... ) const {
if( name != "bobfred" ) { throw badname{}; }
return Foo{ name, .... };
}
};
template<>
struct json_data_constract<Foo> {
using constructor_t = FooConstructor;
using type = json_member_list<json_string<"name">,...>;
};

Here the type Foo will use a callable of type FooConstructor to create all Foo's in the library unless overridden by a mapping.

Per mapping

The json_class mapping's second parameter is that of a Constructor type to call to construct that class and override the default. It can be specified like

json_class<"name", FooConstructor>