Serialization
Introduction
It is frequently required to save some C++ objects in some type of storage like user session or cache and retrieve them back.
It is not a trivial task for C++ - non-reflective language. So CppCMS provides a simple serialization library that helps us to complete such tasks.
CppCMS Serialization Tools
Preparing Objects
Let's assume we have a class person
that holds some information and a list of his children - child
classes.
Person:
struct person { std::string name; std::string family; std::string occupation; std::string martial_state; double salary; physical parameters; std::list<child> children; std::vector<std::string> friends; };
Child:
struct child { std::string name; physical parameters; }
Physical data about them:
struct physical { int age; double height; };
Now, in order to serialize our object we would derive
them from cppcms::serializable
class.
Include <cppcms/serialization.h>
header, and update
the object such that:
struct child { ... }; struct person { ... };
Become
struct child : public cppcms::serializable { ... }; struct person : public cppcms::serializable { ... };
Note, because "physical" object is POD we would handle it in a better way.
Now we add a new member function to the two classes above that describes how to serialize them:
Child:
void serialize(cppcms::archive &a) { a & name & cppcms::as_pod(parameters); }
It receives as parameter cppcms::archive
- an object
that is capable to save/restore that data
and we mark each one of the members: name
and parameters
.
Note, because we know that parameters
is POD object
we use special marker that describes how to copy it.
Next we do the same for person:
void serialize(cppcms::archive &a) { a & name & family & occupation & martial_state & salary & cppcms::as_pod(parameters) & children & friends; }
Note:
The archive
object knows how to deal with standard C++ containers like std::vector
or std::string
. It knows
how to save primitive types like double
as plain binary data.
So for example because children
is std::list<child>
and child
is derived from cppcms::serializable
it
knows how to handle this situation automatically.
If you use your own containers or non-standard containers
you may want to specialize: cppcms::archive_traits
class for your specific class.
Saving and Restoring Objects
Let's assume that std::string buffer
is our data container
So we can save the data to the buffer using these steps:
person john; ... // setup its data cppcms::archive a; john.save(a); // save it to archvive buffer = a.str(); // get the buffer
We can load it as following:
person john; cppcms::archive a; a.str(buffer); john.load(a);
This is very simple way to store and load data but we recommend to use little bit complicated API that would give us more power as we would see later:
Save:
person john; ... // setup its data cppcms::serialization_traits<person>::save(john,buffer);
Load:
person john; cppcms::serialization_traits<person>::load(buffer,john);
Using with Cache and Sessions
Now let's see how we can use CppCMS serialization tools with Cache and Session interfaces:
We can easily cache person objects like this:
person john; if(!cache().fetch_data("john",john)) { init_person(john); cache().store_data("john",john); }
This would allow us for example reduce complex queries to database for some common data that is not updated
We can store the objects within the session:
person me; if(session().is_set("me")) { session().fetch_data("me",me); me.salary += 1; session().store_data("me",me); }
Using 3rd Party Serialization API
Approach
CppCMS API is simple fast and powerful, but it is strictly platform dependent - it does not allow to pass same object between hosts with different architecture or endianess, it does not support versioning etc.
So sometimes you want to use some 3rd party API with CppCMS.
It is quite simple, all you need to do is to provide
specialization for serialization_traits
class - that was the reason we recommended to use
serialization_traits
class rather then cppcms::archive
directly.
Boost.Serialization
Let's show how we use for example Boost.Serialization with CppCMS.
This is our very simple class that supports Boost.Serialization:
struct person { std::string name; std::string family; template<typename Archive> void serialize(Archive &a,unsigned /*version*/) { a & name & family; } };
Let's define two small helper functions to save and load the object to the string:
template<typename T> void load_from_boost(std::string const &src,T &obj) { std::stringbuf ss(src); { boost::archive::binary_iarchive oa(ss); oa >> obj; } } template<typename T> void save_with_boost(T const &obj,std::string &tgt) { std::stringbuf ss; { boost::archive::binary_oarchive oa(ss); oa << obj; } tgt=ss.str(); }
Now all we need is to specialize our serialization_traits
to handle person
properly:
namespace cppcms { template<> struct serialization_traits<person> { static void save(person const &obj,std::string &tgt) { save_with_boost(obj,tgt); } static void load(std::string const &src,person &obj) { load_from_boost(src,obj); } }; }
Then you can freely save and load object using CppCMS session or cache interface:
person john; if(!cache().fetch_data("john",john)) { init_person(john); cache().store_data("john",john); }
← Basic Caching | Top | JSON →