<!--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); |
} |
|
|
|
<!--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);
|
}
|
|
|
|
|