Version 2 (modified by 15 years ago) ( diff ) | ,
---|
Serialization Tutorial
First Steps
In this section we introduce a simple example to show how the serialization works in practice.
Basic serialization
We will introduce Serialization using the PingPong sample provided by Ariba. You will find the following code in {{{PingPongMessage.h}:
#ifndef PINGPONGMESSAGES_H_ #define PINGPONGMESSAGES_H_ #include <string> #include "ariba/ariba.h" using namespace ariba; using std::string; namespace ariba { namespace application { namespace pingpong { using_serialization; class PingPongMessage : public Message { VSERIALIZEABLE; public: PingPongMessage(); PingPongMessage( uint8_t _id, string name = string("<ping>") ); virtual ~PingPongMessage(); string info(); uint8_t getid(); inline string getName() const { return name; } private: uint8_t id; string name; }; }}} // namespace ariba, appplication , pingpong sznBeginDefault( ariba::application::pingpong::PingPongMessage, X ) { X && id && T(name); } sznEnd(); #endif /* PINGPONGMESSAGES_H_ */
The message format for communication between Ariba PingPong instances is defined in the class PingPongMessage
. It inherits from the Message
class and uses the macro VSERIALIZEABLE;
to declare this class as being able to serialize and deserialize itself. Note, that each such class must provide a default constructor that takes no arguments. The PingPongMessage defines two properties id
and name
that it wants to communicate to a remote instance.
To define the actual serialization code, use the following code as template:
sznBeginDefault( CLASSNAME, X ) { X && SERIALIZATION-VARIABLE-1 && SERIALIZATION_VARIABLE-2 && ...; } sznEnd();
As you can see above, CLASSNAME is in the case of the PingPong sample the complate namespace with the class name ariba::application::pingpong::PingPongMessage
. Furthermore the variables that are meant for serialization are combined to the X
using the &&
operator. This operator is invoked both when serializing and when deserializing. Therefore, this is the only special code handling required.
In your {*.cpp} class you require a further macro. In case of the PingPong sample this is simply:
vsznDefault(PingPongMessage);
Non-virtual inline serialization is reasonable on small or bit-sensitive objects (for example IP-Adresses, Ports etc.). To add serialization to an object it must be inherited from the Serializable class and a specification of the SERIALIZEABLE macro:
#include<serialization.h> USING_SERIALIZATION; /* use serialization namespaces */ class IPv4Address : public Serializeable { SERIALIZEABLE private: uint8_t a,b,c,d; public: IPv4Address() { a=1;b=2;c=3;d=4; } };
In the next step, a serializer can be added to this class:
SERIALIZER_BEGIN( IPv4Address, DEFAULT_V, X ) X && a && b && c && d; SERIALIZER_END()
for convenience or personal taste, the macros can also be replaced with
sznBeginDefault( IPv4Address, X ) X && a && b && c && d; sznEnd()
In this case we assume that an IP-Address can be mapped bijectively -- therefore no special treatment of serialization and deserialization is needed. So, what happens here is, that a inline serializer is created for class IPv4Address. DEFAULT_V specifies that this serializer is used as default variant and X specifies the variable of the stream that is used to serialize the object. To serialize this object one can use the data_serialize methods:
IPv4Address addr; Data data = data_serialize( addr ); cout << data << endl;
which outputs
Binary=[01020304]
As you can see the serialization works quite straits forward. The serialized object can now again deserialized with
IPv4Address addr2; data_deserialize( addr2, data );
Be aware that this kind of serialization results in highly-optimized and inlined code. To generate serializers that are not-inlined and generated once per class, in the next section we discuss virtual serialization.