= 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}}}: {{{ #!cpp #ifndef PINGPONGMESSAGES_H_ #define PINGPONGMESSAGES_H_ #include #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("") ); 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: {{{ #!cpp 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. The actual code from !PingPongMessage looks as follows: {{{ #!cpp sznBeginDefault( ariba::application::pingpong::PingPongMessage, X ) { X && id && T(name); } sznEnd(); }}} Note the {{{T()}}} macro that is used for serialization of {{{std::string}}} objects. The following special handlers are provided: * integer support - I( value, length ) * const int support - cI( uintmax_t ) * const char* support - cT( const char* ) * string and char* support, T( char* | std::string ) It is always best to use types that have a specified length, e.g. {{{uint8_t}}}, {{{uint16_t}}}, ... etc. If you are serializing through a In your {*.cpp} class you require a further macro. In case of the !PingPong sample this is simply: {{{ #!cpp 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: {{{ #!cpp #include 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: {{{ #!cpp 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 {{{ #!cpp 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: {{{ #!cpp 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 {{{ #!cpp 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. === Virtual serialization === == Differentiation between serialization and deserialization == == Serialization of bits and special types == == Message specification, serialization and deserialization ==