This is a lightweight header-only solution for serializing objects to and from json using the header-only library picojson.
Make sure picojson.h
can be found, include picojson_serialization.h
, no extra build steps necessary.
Premake4 is included and the generated build files are to be found in the Build folder.
The API is similar to hiberlite's or Boost.Serialization's:
/// A JSON serializable class
struct Point {
double x, y, z;
friend class picojson::convert::access;
template<class Archive>
void json(Archive & ar)
{
ar & picojson::convert::member("x", x);
ar & picojson::convert::member("y", y);
ar & picojson::convert::member("z", z);
}
};
/// Composed serialization is possible
struct NamedPoint {
std::string name;
Point point;
friend class picojson::convert::access;
template<class Archive>
void json(Archive & ar)
{
ar & picojson::convert::member("name", name);
ar & picojson::convert::member("point", point);
}
};
To enable std::vector
serialization, use the header picojson_vector_serializer.h
NamedPoint np = { "test point" , { 1 , 2 , 3 } };
picojson::value npv = picojson::convert::to_value(np);
std::string nps = picojson::convert::to_string(np);
resulting in
{"name":"test point","point":{"x":1,"y":2,"z":3}}
NamedPoint np;
std::string json=...
picojson::convert::from_string(json,np);
Currently, if deserialization fails for a member, that member is not modified.
A class that cannot be extended, but the internals are accessible (following to the Boost.Serialization api):
struct Untouchable {
int value;
};
With a free function defined in the ::picojson::convert
namespace,
namespace picojson {
namespace convert {
template <class Archive>
void json(Archive &ar, Untouchable &u) {
ar &picojson::convert::member("value", u.value);
}
}
}
serialization is again possible:
Untouchable example = { 42 };
std::string example_string( picojson::convert::to_string(example) );
Untouchable example_deserialized = { 0 };
picojson::convert::from_string( example_string, example_deserialized );
CHECK( example.value == example_deserialized.value );
The serialization can be easily customized for types that are not default-convertible. Example class:
struct Example {
enum Status {
NONE = 0,
SOME,
SOME_OTHER
};
Status status;
friend class picojson::convert::access;
template<class Archive>
void json(Archive & ar)
{
ar & picojson::convert::member("status", status);
}
};
Attempting to serialize instances of Example
should lead to compile error:
Example e = { Example::NONE };
picojson::value ev = picojson::convert::to_value(e);
However, you can specialize the value converter for the enum, i.e.:
namespace picojson {
namespace convert {
template<> struct value_converter<Example::Status> {
static value to_value(Example::Status v) {
return value(static_cast<double>(v));
}
static void from_value(value const& ov, Example::Status& v) {
if ( ov.is<double>() ) v = Example::Status(static_cast<int>(ov.get<double>()));
}
};
}
}
and the test passes:
Example e = { Example::SOME };
picojson::value ev = picojson::convert::to_value(e);
CHECK(has<double>(ev, "status", static_cast<int>(Example::SOME)));
- vector
- map
- multimap
If you have serializable types that may be unrelated, such as a logic component and a data transfer object, you can 'project' the data from one object to another simply by mapping the values through the serialization like so:
Class1 c1=...;
Class2 c2=picojson::project::from(c1).onto<Class2>();
Copyright 2013, Dmitry Ledentsov MIT License: http://www.opensource.org/licenses/mit-license.php