This is a lightweight header-only solution for serializing objects to and from json using the header-only library picojson.
Current release: v0.10
a more feature-rich alternative: cereal
Make sure picojson.h
can be found, include picojson_serialization.h
, no extra build steps necessary.
Premake5 is included and can be used to generate build files in the Build folder. To build and run the tests, do:
[path_to]/premake5 gmake
make -C Build
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);
}
};
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 );
To enable std::vector
serialization, use the header picojson_vector_serializer.h
and likewise for the other supported container types.
- vector
- map
- multimap
- set
- multiset
To serialize const
data types (including the keys of std::map
, std::multimap
, std::set
, and std::multiset
), the json()
member must be overloaded for const
objects. The normal void(Archive&)
function template as explained above works on non-const
objects (Point
and NamedPoint
in the above example). If a const
object is to be serialized, an additional const
version of the json()
function must be defined. E.g.
struct NamedPoint {
// in addition to the non-const version
template<class Archive>
void json(Archive & ar) const
{
ar & picojson::convert::member("name", name);
ar & picojson::convert::member("point", point);
}
};
Free function version can also be overloaded
template <class Archive>
void json(Archive &ar, Point const &p) {
ar & ...
}
as a convenience, the function picojson::convert::init_from_string
can be used instead of from_string
to default-initialize the object before deserialization.
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)));
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
- Copyright 2014, project contributors
- MIT License
- picojson as the main dependency
- msinttypes for in64 in MSVC
- premake for generating build files
Dependencies retain their respective licenses