<!--toc-->
|
|
## 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 provide 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`](/cppcms_ref_v0_99/structcppcms_1_1archive__traits.html)
|
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 withing 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][prev]
|
| [Top](#maincontent)
|
| [JSON][next] →
|
|
|
[prev]: /wikipp/en/page/cppcms_1x_basic_caching
|
[next]: /wikipp/en/page/cppcms_1x_json |