Gobject serialisation

From Buzztard

Jump to: navigation, search

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

Links to OO-2-XML mappings:

Personal tools
collaboration

SourceForge Logo

GStreamer Logo

Linux Sound Logo

MediaWiki

Valgrind

GNU Library Public Licence

GNU Free Documentation License 1.2