Gobject serialisation
From Buzztard
darace The goal is to lessen the maintenance work. When now adding fields to songs classes, one also needs to add code to load/save methods in the BtSongIONative io modules to make these fields persistent. We also need this for cut/copy/paste to serialize parts of out document and load partial fragments.
Idea 1 is to add metadata fields as qdata to allow serialisation/deserialisation of GObjects. Advantage here is that is less intrusive for objects and allows for different serialisation formats.
Idea 2 is to add a Serializeable interface to objects. The interface has serialize and desezialize methods (aka: load_myself, save_myself). Advantage here is that it is easy to implement as objects know what need to be serialized.
Contents |
[edit] Introspection
[edit] simple cases
These examples can be done without any extensions.
[edit] simple example case
code:
class object1 {
gulong numeric_property=5;
gchar text_property="test";
}
xml:
<object1 numeric_property="5" text_property="test"/>
[edit] containment example case
code:
class object2 {
gchar id;
}
class object1 {
gulong numeric_property=5;
gchar text_property="test";
object2 { id="1"; }
object2 { id="2"; }
}
xml:
<object1 numeric_property="5" text_property="test"> <object2 id="1"/> <object3 id="1"/> </object1>
[edit] extended cases
These examples need special metadata.
[edit] volatile example
code:
class object1 {
gulong numeric_property=5;
gchar text_property="test";
glong runtime_value=10; /* GSerialize::Flags=Volatile */
}
xml:
<object1 numeric_property="5" text_property="test"/>
[edit] collection example
class object2 {
gchar id;
}
class object1 {
gulong numeric_property=5;
gchar text_property="test";
GList object_list; /* GSerialize::CollectionName="children" */
}
xml:
<object1 numeric_property="5" text_property="test">
<children>
<object2 id="1"/>
<object3 id="1"/>
</children>
</object1>
[edit] implementation
A class registers its properties with the GType system via GParamsSpecs. These GParamSpecs are GObjects themself. Thus one can do
pspec = g_param_spec_glong("runtime_value", "runtime value prop", "a long interger to control ...",
0, 100, 0, G_PARAM_READWRITE);
g_object_set_qdata(pspec, GSerializeFlagsQuark, G_SERIALIZE_FLAGS_VOLATILE);
g_object_class_install_property(gobject_class, MY_OBJECT_NAME, pspec);
Next we need a GXMLPersistence (or also GMySQLPersistence if you want one).
GXMLPersistence xml_persistence;
xml_persistence = g_xml_persistence_new("mydata.xml");
g_xml_persistence_serialize(xml_persistence,G_OBJECT(my_root));
g_object_unref(xml_persistence);
The de-serializer will read in the data and uses
g_object_new(obj_type,"par0",val0,...,NULL);
(TODO: needs to get obj_type by name)
The beauty of the approach is that is requires less work than writing
save_myself load_myself
functions and it is format agnostic.
[edit] problems
[edit] hidden collection types
What if a collection type (list, hasmap, array) is private and the object has methods like:
my_object_add_item(obj,item); my_object_del_item(obj,item);
Serialisation code can not access the collection to store items and the deserialisation code cannot add items back.
Exposing the collection as a read-only member does not help in cases when the add_function does something else.
[edit] constructors
In the gobject world it is common to have g_<type>_new() methods. As long as they are only wrappers for g_object_new(type,...) it's okay. Problems start when they do post-construction, as the de-serialisation code does not know about them.
[edit] gst-controller
Controllable GObject properties have not just one value, but a value that depends on time. This does not cause problems for buzztard, as we store the time dependency in our patterns and build the controller queue at runtime.
[edit] Interface
In this idea all serializable objects would implement two methods:
- bt_persistence_save(object,node,selection);
- bt_persistence_load(object,node,location);
where node is an XmlNode*.
selection and location are abstract basetypes and need to be derived locally for each class.
For the future it would be nice to abstract the stream, so that we don't supply the XmlNode * and do xml operations on it, but instead a stream. For that we need to do some reasearch on what operations we need to do on the stream.
[edit] links
Links to discussion and other approaches
- http://bugzilla.gnome.org/show_bug.cgi?id=157734
- http://gwyddion.net/documentation/cvs/libgwyddion/libgwyddion-gwyserializable.php
- http://gnome.org/~robsta/gopersist/docs/reference/
Links to OO-2-XML mappings:



