[gxml/serialization_isolation] Xom,Jgs merging: re-namespace things



commit 1b1db425a05857a94d3979b73bf37c2a47478eef
Author: Richard Schwarting <aquarichy gmail com>
Date:   Wed Apr 2 11:16:06 2014 -0400

    Xom,Jgs merging: re-namespace things

 gxml/Makefile.am                                   |   24 +-
 gxml/Serializable.vala                             |  567 --------------------
 gxml/SerializableObjectModel.vala                  |  381 -------------
 gxml/jgs/JgsSerializable.vala                      |  363 +++++++++++++
 .../JgsSerialization.vala}                         |  434 ++++++++++-----
 gxml/{ => xom}/Enumeration.vala                    |    2 +-
 gxml/{ => xom}/SerializableContainer.vala          |    4 +-
 gxml/{ => xom}/SerializableGeeArrayList.vala       |    2 +-
 gxml/{ => xom}/SerializableGeeDualKeyMap.vala      |    2 +-
 gxml/{ => xom}/SerializableGeeHashMap.vala         |    2 +-
 gxml/{ => xom}/SerializableGeeTreeMap.vala         |    2 +-
 gxml/{ => xom}/SerializableJson.vala               |    2 +-
 gxml/{ => xom}/SerializableMapDualKey.vala         |    2 +-
 gxml/{ => xom}/SerializableMapKey.vala             |    2 +-
 gxml/xom/SerializableObjectModel.vala              |  383 +++++++++++++
 15 files changed, 1068 insertions(+), 1104 deletions(-)
---
diff --git a/gxml/Makefile.am b/gxml/Makefile.am
index 8dd9cbb..1c174a5 100644
--- a/gxml/Makefile.am
+++ b/gxml/Makefile.am
@@ -57,17 +57,21 @@ libgxml_0_4_la_SOURCES = \
        ProcessingInstruction.vala \
        Text.vala \
        Serializable.vala \
-       Enumeration.vala \
-       SerializableObjectModel.vala \
-       SerializableJson.vala \
+       jgs/JgsSerializable.vala \
+       jgs/JgsSerialization.vala \
+       xom/XomSerializable.vala \
+       xom/Enumeration.vala \
+       xom/SerializableObjectModel.vala \
+       xom/SerializableJson.vala \
        Serialization.vala \
-       SerializableGeeTreeMap.vala \
-       SerializableGeeHashMap.vala \
-       SerializableMapKey.vala \
-       SerializableGeeDualKeyMap.vala \
-       SerializableMapDualKey.vala \
-       SerializableGeeArrayList.vala \
-       SerializableContainer.vala
+       xom/XomSerialization.vala \
+       xom/SerializableGeeTreeMap.vala \
+       xom/SerializableGeeHashMap.vala \
+       xom/SerializableMapKey.vala \
+       xom/SerializableGeeDualKeyMap.vala \
+       xom/SerializableMapDualKey.vala \
+       xom/SerializableGeeArrayList.vala \
+       xom/SerializableContainer.vala
 
 gxml_0_4_la_vala.stamp: $(libgxml_0_4_la_SOURCES)
 
diff --git a/gxml/jgs/JgsSerializable.vala b/gxml/jgs/JgsSerializable.vala
new file mode 100644
index 0000000..a47d974
--- /dev/null
+++ b/gxml/jgs/JgsSerializable.vala
@@ -0,0 +1,363 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Serializable.vala
+ *
+ * Copyright (C) 2011-2013  Richard Schwarting <aquarichy gmail com>
+ * Copyright (C) 2013  Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Richard Schwarting <aquarichy gmail com>
+ *      Daniel Espinosa <esodan gmail com>
+ */
+
+
+/*
+  Version 3: json-glib version
+
+  PLAN:
+  * add support for GObject Introspection to allow us to serialise non-property members
+
+  json-glib
+  * has functions to convert XML structures into Objects and vice versa
+  * can convert simple objects automatically
+  * richer objects need to implement interface
+
+  json_serializable_real_serialize -> json_serialize_pspec
+  * how do these get used with GInterfaces?  are these default methods like with superclasses?
+  * TODO: I don't think vala does multiple inheritance, so do we want GXml.Serializable to be an interface 
or a superclass?
+
+  json_serializable_default_{de,}serialize_property -> json_serializable_real_{de,}serialize
+
+  json_serializable_{de,}serialize_property -> iface->{de,}serialize_property
+    these all get init'd to -> json_serializable_real_{de,}serialize_property
+      these all call -> json_{de,}serialize_pspec
+
+  json_serializable_{find,list,get,set}_propert{y,ies} -> iface->{find,list,get,set}_propert{y,ies}
+    these all get init'd to -> json_serializable_real_{find,list,get,set}_propert{y,ies}
+         these all call -> g_object_{class,}_{find,list,get,set}_propert{y,ies}
+ */
+
+using GXml;
+
+namespace GXml.Jgs {
+       /**
+        * Interface allowing implementors direct control over serialisation of properties and other data
+        *
+        * A class that implements this interface will still be passed
+        * to { link GXml.Serialization.serialize_object} for
+        * serialization.  That function will check whether the object
+        * implements { link GXml.Serializable} and will then prefer
+        * overridden methods instead of standard ones.  Most of the
+        * methods for this interface can indicate (via return value)
+        * that, for a given property, the standard serialization
+        * approach should be used instead.  Indeed, not all methods
+        * need to be implemented, but some accompany one another and
+        * should be implemented carefully, corresponding to one
+        * another.  You can also create virtual properties from
+        * non-public property fields to enable their serialization.
+        *
+        * For an example, look in tests/XmlSerializableTest
+        */
+       public interface Serializable : GLib.Object, GXml.Serializable {
+               /**
+                * Handles serializing potential tasks beyond
+                * serializing individual properties.
+                *
+                * { link doc} is the { link GXml.Document} that will
+                * ultimately contain the serialized object.  You can
+                * use it to create the { link GXml.Node}s you want to
+                * add from here to the serialized object, like
+                * { link GXml.Element}s, { link GXml.DocumentFragment}s,
+                * and { link GXml.Text}s.  Return your completed XML
+                * structure as a { link GXml.Node} and it will be
+                * added to an <Object> element in the serialized XML.
+                *
+                * Example:
+                *
+                * Say we have a { link GLib.Object}, Cookie, which
+                * looks like this in Vala,
+                *
+                * {{{
+                * class Cookie {
+                *   string flavour {}
+                *   int mass {}
+                * }
+                * }}}
+                *
+                * The default serialized XML might look like this
+                *
+                * {{{
+                * <Object otype="Cookie" oid="0xC00C1E5">
+                *   <Property ptype="gchar*" pname="flavour">Chocolate chip</Property>
+                *   <Property ptype="int" pname="mass">28</Property>
+                * </Object>
+                * }}}
+                *
+                * If we want additional information not connected to
+                * any of the properties, we could extend the Cookie
+                * class like this:
+                *
+                * {{{
+                * class Cookie : Serializable {
+                *   string flavour {}
+                *   int mass {}
+                *   public override Node? serialize (Document doc)
+                *     throws SerializationError {
+                *     return doc.create_comment ("<!-- baked on Nov 16 2013 by Wallace Wells -->");
+                *   }
+                * }}}
+                *
+                * This would result in the following serialized XML:
+                *
+                * {{{
+                * <Object otype="Cookie" oid="0xC00C1E5">
+                *   <!-- baked on Nov 16 2013 by Wallace Wells -->
+                *   <Property ptype="gchar*" pname="flavour">Chocolate chip</Property>
+                *   <Property ptype="int" pname="mass">28</Property>
+                * </Object>
+                * }}}
+                *
+                * If you want to completely handle serialization of
+                * your object yourself in { link Serializable.serialize},
+                * you can prevent automatic serialization of properties
+                * by overriding { link Serializable.serialize_property}
+                * and simply returning true.
+                *
+                * @param doc The { link GXml.Document} that contains serialized XML, used to create new { 
link GXml.Node}s
+                *
+                * @return A { link GXml.Node} representing serialized content from the implementing object
+                */
+               public virtual GXml.Node?
+               serialize (GXml.Document doc) {
+                       return null;
+               }
+
+               /**
+                * Handles serializing individual properties.
+                *
+                * Interface method to handle serialization of an
+                * individual property.  The implementing class
+                * receives a description of it, and should create a
+                * { link GXml.Node} that encapsulates the property.
+                * { link GXml.Serialization} will embed the { link GXml.Node} into
+                * a "Property" { link GXml.Element}, so the { link GXml.Node}
+                * returned can often be something as simple as
+                * { link GXml.Text}.
+                *
+                * To let { link GXml.Serialization} attempt to automatically
+                * serialize the property itself, do not implement
+                * this method.  If the method returns %NULL,
+                * { link GXml.Serialization} will attempt handle it itself.
+                *
+                * @param property_name String name of a property to serialize
+                * @param spec The { link GLib.ParamSpec} describing the property
+                * @param doc The { link GXml.Document} the returned { link GXml.Node} should belong to
+                *
+                * @return a new { link GXml.Node}, or %NULL
+                */
+               public virtual GXml.Node?
+               serialize_property (string property_name,
+                                   GLib.ParamSpec spec,
+                                   GXml.Document doc) {
+                       return null;
+               }
+
+               /**
+                * Handle deserialization of an object beyond its
+                * properties.
+                *
+                * This can cover deserialization tasks outside of
+                * just properties, like initialising variables
+                * normally handled by a constructor.  (Note that when
+                * deserializing, an object's constructor is not
+                * called.)
+                *
+                * @param serialized_node The XML representation of this object
+                */
+               public virtual void
+               deserialize (GXml.Node serialized_node) {
+                       return;
+               }
+
+               /* TODO: consider making the visibility of all of
+                * these interface virtual methods to protected or
+                * internal.  In theory, only Serialization should
+                * need to actually see them.
+                */
+
+               /**
+                * Handles deserializing individual properties.
+                *
+                * Interface method to handle deserialization of an
+                * individual property.  The implementing class
+                * receives a description of the property and the
+                * { link GXml.Node} that contains the content.  The
+                * implementing { link GXml.Serializable} object can extract
+                * the data from the { link GXml.Node} and store it in its
+                * property itself. Note that the { link GXml.Node} may be
+                * as simple as a { link GXml.Text} that stores the data as a
+                * string.
+                *
+                * If the implementation has handled deserialization,
+                * return true.  Return false if you want
+                * { link GXml.Serialization} to try to automatically
+                * deserialize it.  If { link GXml.Serialization} tries to
+                * handle it, it will want either { link GXml.Serializable}'s
+                * set_property (or at least { link GLib.Object.set_property})
+                * to know about the property.
+                *
+                * @param property_name the name of the property as a string
+                * @param spec the { link GLib.ParamSpec} describing the property
+                * @param property_node the { link GXml.Node} encapsulating data to deserialize
+                * @return `true` if the property was handled, `false` if { link GXml.Serialization} should 
handle it
+                */
+               /*
+                * @todo: consider not giving property_name, but
+                * letting them get name from spec
+                * @todo: consider returning { link GLib.Value} as out param
+                */
+               public virtual bool
+               deserialize_property (string property_name,
+                                     GLib.ParamSpec spec,
+                                     GXml.Node property_node) {
+                       return false; // default deserialize_property gets used
+               }
+
+
+               /* Correspond to: g_object_class_{find_property,list_properties} */
+
+               /*
+                * Handles finding the { link GLib.ParamSpec} for a given property.
+                *
+                * @param property_name the name of a property to obtain a { link GLib.ParamSpec} for
+                * @return a { link GLib.ParamSpec} describing the named property
+                *
+                * { link GXml.Serialization} uses { link
+                * GLib.ObjectClass.find_property} (as well as { link
+                * GLib.ObjectClass.list_properties}, { link
+                * GLib.Object.get_property}, and { link
+                * GLib.Object.set_property}) to manage serialization
+                * of properties.  { link GXml.Serializable} gives the
+                * implementing class an opportunity to override
+                * { link GLib.ObjectClass.find_property} to control
+                * what properties exist for { link GXml.Serialization}'s
+                * purposes.
+                *
+                * For instance, if an object has private data fields
+                * that are not installed public properties, but that
+                * should be serialized, find_property can be defined
+                * to return a { link GLib.ParamSpec} for non-installed
+                * properties.  Other { link GXml.Serializable} functions
+                * should be consistent with it.
+                *
+                * An implementing class might wish to maintain such
+                * { link GLib.ParamSpec} s separately, rather than creating new
+                * ones for each call.
+                */
+               public virtual unowned GLib.ParamSpec? find_property (string property_name) {
+                       return this.get_class ().find_property (property_name); // default
+               }
+
+               /*
+                * List the known properties for an object's class
+                *
+                * @return an array of { link GLib.ParamSpec} of
+                * "properties" for the object.
+                *
+                * { link GXml.Serialization} uses
+                * { link GLib.ObjectClass.list_properties} (as well as
+                * { link GLib.ObjectClass.find_property},
+                * { link GLib.Object.get_property}, and { link GLib.Object.set_property})
+                * to manage serialization of an object's properties.
+                * { link GXml.Serializable} gives an implementing class an
+                * opportunity to override
+                * { link GLib.ObjectClass.list_properties} to control which
+                * properties exist for { link GXml.Serialization}'s purposes.
+                *
+                * For instance, if an object has private data fields
+                * that are not installed public properties, but that
+                * should be serialized, list_properties can be
+                * defined to return a list of { link GLib.ParamSpec} s covering
+                * all the "properties" to serialize.  Other
+                * { link GXml.Serializable} functions should be consistent
+                * with it.
+                *
+                * An implementing class might wish to maintain such
+                * { link GLib.ParamSpec} s separately, rather than creating new
+                * ones for each call.
+                */
+               public virtual unowned GLib.ParamSpec[] list_properties () {
+                       return this.get_class ().list_properties ();
+               }
+
+               /*
+                * Get a string version of the specified property
+                *
+                * @param spec The property we're retrieving as a string
+                *
+                * { link GXml.Serialization} uses { link GLib.Object.get_property} (as
+                * well as { link GLib.ObjectClass.find_property},
+                * { link GLib.ObjectClass.list_properties}, and
+                * { link GLib.Object.set_property}) to manage serialization of
+                * an object's properties.  { link GXml.Serializable} gives an
+                * implementing class an opportunity to override
+                * { link GLib.Object.get_property} to control what value is
+                * returned for a given parameter.
+                *
+                * For instance, if an object has private data fields
+                * that are not installed public properties, but that
+                * should be serialized,
+                * { link GXml.Serializable.get_property} can be used to
+                * handle this case as a virtual property, supported
+                * by the other { link GXml.Serializable} functions.
+                *
+                * `spec` is usually obtained from list_properties or find_property.
+                *
+                * As indicated by its name, `str_value` is a { link GLib.Value}
+                * that wants to hold a string type.
+                *
+                * @todo: why not just return a string? :D Who cares
+                * how analogous it is to { link GLib.Object.get_property}? :D
+                */
+               public virtual void get_property (GLib.ParamSpec spec, ref GLib.Value str_value) {
+                       ((GLib.Object)this).get_property (spec.name, ref str_value);
+               }
+               /*
+                * Set a property's value.
+                *
+                * @param spec Specifies the property whose value will be set
+                * @param value The value to set the property to
+                *
+                * { link GXml.Serialization} uses { link GLib.Object.set_property} (as
+                * well as { link GLib.ObjectClass.find_property},
+                * { link GLib.ObjectClass.list_properties}, and
+                * { link GLib.Object.get_property}) to manage serialization of
+                * an object's properties.  { link GXml.Serializable} gives an
+                * implementing class an opportunity to override
+                * { link GLib.Object.set_property} to control how a property's
+                * value is set.
+                *
+                * For instance, if an object has private data fields
+                * that are not installed public properties, but that
+                * should be serialized,
+                * { link GXml.Serializable.set_property} can be used to
+                * handle this case as a virtual property, supported
+                * by the other { link GXml.Serializable} functions.
+                */
+               public virtual void set_property (GLib.ParamSpec spec, GLib.Value value) {
+                       ((GLib.Object)this).set_property (spec.name, value);
+               }
+       }
+}
diff --git a/gxml/Serialization.vala b/gxml/jgs/JgsSerialization.vala
similarity index 51%
rename from gxml/Serialization.vala
rename to gxml/jgs/JgsSerialization.vala
index f90ff54..4a5fa0a 100644
--- a/gxml/Serialization.vala
+++ b/gxml/jgs/JgsSerialization.vala
@@ -48,29 +48,17 @@ namespace GXml {
         */
        public errordomain SerializationError {
                /**
-                * An unknown { link GLib.Type} was encountered.
+                * An object without a known { link GLib.Type} was encountered.
                 */
                UNKNOWN_TYPE,
                /**
-                * A property was described in XML that is not known { link GLib.Type}.
+                * A property was described in XML that is not known to the object's type.
                 */
                UNKNOWN_PROPERTY,
                /**
-                * Serialization/Deserialization is unsupported for given object type
+                * An object with a known { link GLib.Type} that we do not support was encountered.
                 */
-               UNSUPPORTED_OBJECT_TYPE,
-               /**
-                * Serialization/Deserialization is unsupported for given property type
-                */
-               UNSUPPORTED_PROPERTY_TYPE,
-               /**
-                * Serialization/Deserialization is unsupported for given { link GLib.Type}
-                */
-               UNSUPPORTED_TYPE,
-               /**
-                * Serialization/Deserialization is unsupported for given XML structure
-                */
-               UNSUPPORTED_FILE_FORMAT
+               UNSUPPORTED_TYPE
        }
 
        /**
@@ -99,11 +87,7 @@ namespace GXml {
                 * { link GLib.Value} can transform into a string, and
                 * operates recursively.
                 */
-               private static GXml.Node serialize_property (GLib.Object object,
-                                                            ParamSpec prop_spec,
-                                                            GXml.Document doc)
-                                                                                        throws GLib.Error
-               {
+               private static GXml.Node serialize_property (GLib.Object object, ParamSpec prop_spec, 
GXml.Document doc) throws SerializationError {
                        Type type;
                        Value value;
                        Node value_node;
@@ -128,13 +112,21 @@ namespace GXml {
                                   it truly is the latter, but is returned as the
                                   former by list_properties) */
                                value = Value (typeof (int));
-                               object.get_property (prop_spec.name, ref value);
+                               if (serializable != null) {
+                                       serializable.get_property (prop_spec, ref value);
+                               } else {
+                                       object.get_property (prop_spec.name, ref value);
+                               }
                                value_node = doc.create_text_node ("%d".printf (value.get_int ()));
                                /* TODO: in the future, perhaps figure out GEnumClass
                                         and save it as the human readable enum value :D */
                        } else if (Value.type_transformable (prop_spec.value_type, typeof (string))) { // 
e.g. int, double, string, bool
                                value = Value (typeof (string));
-                               object.get_property (prop_spec.name, ref value);
+                               if (serializable != null) {
+                                       serializable.get_property (prop_spec, ref value);
+                               } else {
+                                       object.get_property (prop_spec.name, ref value);
+                               }
                                value_node = doc.create_text_node (value.get_string ());
                        } else if (type == typeof (GLib.Type)) {
                                value_node = doc.create_text_node (type.name ());
@@ -160,27 +152,30 @@ namespace GXml {
                                0x7ffff7b7d67c "dup func", qdata = 0x0, ref_count = 4, param_id = 2}
 */
                        } else if (type.is_a (typeof (GLib.Object))
-                                  && ! type.is_a (typeof (Gee.Collection)))
-                         {
-                                       GLib.Object child_object;
-
-                                       // TODO: this is going to get complicated
-                                       value = Value (typeof (GLib.Object));
+                                  && ! type.is_a (typeof (Gee.Collection))) {
+                               GLib.Object child_object;
+
+                               // TODO: this is going to get complicated
+                               value = Value (typeof (GLib.Object));
+                               if (serializable != null) {
+                                       serializable.get_property (prop_spec, ref value);
+                               } else {
                                        object.get_property (prop_spec.name, ref value);
                                        /* This can fail; consider case of Gee.TreeSet that isn't special 
cased above, gets error
-                                                
(/home/richard/mine/development/gnome/gdom/gxml/test/.libs/gxml_test:10996):
-                                                GLib-GObject-CRITICAL **: Read-only property 
'read-only-view' on class 'GeeReadOnlyBidirSortedSet' has type
-                                                'GeeSortedSet' which is not equal to or more restrictive 
than the type 'GeeBidirSortedSet' of the property
-                                                on the interface 'GeeBidirSortedSet' */
-                                       child_object = value.get_object ();
-                                       Document value_doc = Serialization.serialize_object (child_object); 
// catch serialisation errors?
-
-                                       value_node = doc.copy_node (value_doc.document_element);
+                                          
(/home/richard/mine/development/gnome/gdom/gxml/test/.libs/gxml_test:10996):
+                                          GLib-GObject-CRITICAL **: Read-only property 'read-only-view' on 
class 'GeeReadOnlyBidirSortedSet' has type
+                                          'GeeSortedSet' which is not equal to or more restrictive than the 
type 'GeeBidirSortedSet' of the property
+                                          on the interface 'GeeBidirSortedSet' */
+                               }
+                               child_object = value.get_object ();
+                               Document value_doc = Serialization.serialize_object (child_object); // catch 
serialisation errors?
+
+                               value_node = doc.copy_node (value_doc.document_element);
                        } else if (type.name () == "gpointer") {
                                GLib.warning ("DEBUG: skipping gpointer with name '%s' of object '%s'", 
prop_spec.name, object.get_type ().name ());
                                value_node = doc.create_text_node (prop_spec.name);
                        } else {
-                               throw new SerializationError.UNSUPPORTED_PROPERTY_TYPE ("Can't currently 
serialize type '%s' for property '%s' of object '%s'", type.name (), prop_spec.name, object.get_type ().name 
());
+                               throw new SerializationError.UNSUPPORTED_TYPE ("Can't currently serialize 
type '%s' for property '%s' of object '%s'", type.name (), prop_spec.name, object.get_type ().name ());
                        }
 
                        return value_node;
@@ -210,68 +205,82 @@ namespace GXml {
                 * @param object A { link GLib.Object} to serialize
                 * @return a { link GXml.Document} representing the serialized `object`
                 */
-               public static GXml.Document serialize_object (GLib.Object object) throws GLib.Error
-               {
+               public static GXml.Document serialize_object (GLib.Object object) throws SerializationError {
                        Document doc;
                        Element root;
                        ParamSpec[] prop_specs;
                        Element prop;
+                       Serializable serializable = null;
                        Node value_prop = null;
                        string oid;
 
-                       Serialization.init_caches ();
-                       /* Create an XML Document to return the object
-                       in.  TODO: consider just returning an
-                       <Object> node; but then we'd probably want
-                       a separate document for it to already be a
-                       part of as its owner_document. */
-                       doc = new Document ();
-                       if (object is Serializable) {
-                               ((Serializable) object).serialize (doc);
-                               return doc;
-                       }
                        // If the object has been serialized before, let's not do it again!
                        oid = "%p".printf (object);
-                       // first, check if its been serialised already, and if so, just return an ObjectRef 
element for it.
-                       if (oid != "" && Serialization.serialize_cache.contains (oid)) {
-                               // GLib.message ("cache hit on oid %s", oid);
-                               root = doc.create_element ("ObjectRef");
+                       Serialization.init_caches ();
+
+                       try {
+                               /* Create an XML Document to return the object
+                                  in.  TODO: consider just returning an
+                                  <Object> node; but then we'd probably want
+                                  a separate document for it to already be a
+                                  part of as its owner_document. */
+                               doc = new Document ();
+
+                               // first, check if its been serialised already, and if so, just return an 
ObjectRef element for it.
+                               if (oid != "" && Serialization.serialize_cache.contains (oid)) {
+                                       // GLib.message ("cache hit on oid %s", oid);
+                                       root = doc.create_element ("ObjectRef");
+                                       doc.append_child (root);
+                                       root.set_attribute ("otype", object.get_type ().name ());
+                                       root.set_attribute ("oid", oid);
+                                       return doc;
+                               }
+
+                               if (object.get_type ().is_a (typeof (Serializable))) {
+                                       serializable = (Serializable)object;
+                               }
+
+                               root = doc.create_element ("Object");
                                doc.append_child (root);
                                root.set_attribute ("otype", object.get_type ().name ());
                                root.set_attribute ("oid", oid);
-                               return doc;
-                       }
 
-                       if (object is Serializable) {
-                               ((Serializable) object).serialize (doc);
-                               Serialization.serialize_cache.set (oid, doc.document_element);
-                               return doc;
-                       }
-                       // For now and on assume is not a Serializable object
-                       root = doc.create_element ("Object");
-                       doc.append_child (root);
-                       root.set_attribute ("otype", object.get_type ().name ());
-                       root.set_attribute ("oid", oid);
-                       // Cache this before we start exploring properties in case there's a cycle
-                       Serialization.serialize_cache.set (oid, root);
-
-                       /* TODO: make sure we don't use an out param for our returned list
-                          size in our interface's list_properties (), using
-                          [CCode (array_length_type = "guint")] */
-                       prop_specs = object.get_class ().list_properties ();
-
-                       /* Exam the properties of the object and store
-                          them with their name, type and value in XML
-                          Elements.  Use GValue to convert them to
-                          strings. (Too bad deserialising isn't that
-                          easy w.r.t. string conversion.) */
-                       foreach (ParamSpec prop_spec in prop_specs) {
-                               prop = doc.create_element ("Property");
-                               prop.set_attribute ("ptype", prop_spec.value_type.name ());
-                               prop.set_attribute ("pname", prop_spec.name);
-                               value_prop = Serialization.serialize_property (object, prop_spec, doc);
-                               prop.append_child (value_prop);
-                               root.append_child (prop);
+                               // Cache this before we start exploring properties in case there's a cycle
+                               Serialization.serialize_cache.set (oid, root);
+
+                               /* TODO: make sure we don't use an out param for our returned list
+                                  size in our interface's list_properties (), using
+                                  [CCode (array_length_type = "guint")] */
+                               if (serializable != null) {
+                                       prop_specs = serializable.list_properties ();
+                               } else {
+                                       prop_specs = object.get_class ().list_properties ();
+                               }
+
+                               /* Exam the properties of the object and store
+                                  them with their name, type and value in XML
+                                  Elements.  Use GValue to convert them to
+                                  strings. (Too bad deserialising isn't that
+                                  easy w.r.t. string conversion.) */
+                               foreach (ParamSpec prop_spec in prop_specs) {
+                                       prop = doc.create_element ("Property");
+                                       prop.set_attribute ("ptype", prop_spec.value_type.name ());
+                                       prop.set_attribute ("pname", prop_spec.name);
+
+                                       value_prop = null;
+                                       if (serializable != null) {
+                                               value_prop = serializable.serialize_property (prop_spec.name, 
prop_spec, doc);
+                                       }
+                                       if (value_prop == null) {
+                                               value_prop = Serialization.serialize_property (object, 
prop_spec, doc);
+                                       }
+
+                                       prop.append_child (value_prop);
+                                       root.append_child (prop);
+                               }
+                       } catch (GLib.Error e) {
+                               GLib.error ("%s", e.message);
+                               // TODO: handle this better
                        }
 
                        /* Debug output */
@@ -289,39 +298,63 @@ namespace GXml {
                 * strings back to other types, we use our own function to do
                 * that.
                 */
-               private static void deserialize_property (ParamSpec spec, Element prop_elem,
-                                                         out Value val)
-                                                         throws GLib.Error
-               {
+               private static void deserialize_property (ParamSpec spec, Element prop_elem, out Value val) 
throws SerializationError {
                        Type type;
+
                        type = spec.value_type;
+
+                       // if (false || ptype != "") {
+                       //      // TODO: undisable if we support fields at some point
+                       //      type = Type.from_name (ptype);
+                       //      if (type == 0) {
+                       //              /* This probably shouldn't happen while we're using
+                       //                 ParamSpecs but if we support non-property fields
+                       //                 later, it might be necessary again :D */
+                       //              throw new SerializationError.UNKNOWN_TYPE ("Deserializing object '%s' 
has property '%s' with unknown type '%s'", otype, pname, ptype);
+                       //      }
+                       // }
+
                        // Get value and save this all as a parameter
+                       bool transformed = false;
                        val = Value (type);
                        if (GLib.Value.type_transformable (type, typeof (string))) {
-                                       Serializable.string_to_gvalue (prop_elem.content, ref val);
+                               try {
+                                       string_to_gvalue (prop_elem.content, ref val);
+                                       transformed = true;
+                               } catch (SerializationError e) {
+                                       throw new SerializationError.UNSUPPORTED_TYPE ("string_to_gvalue 
should transform it but failed");
+                               }
+                       // } else if (type.is_a (typeof (Gee.Collection))) {
                        } else if (type.is_a (typeof (GLib.Object))) {
                                GXml.Node prop_elem_child;
                                Object property_object;
+
                                prop_elem_child = prop_elem.first_child;
-                               property_object = Serialization.deserialize_object_from_node 
(prop_elem_child);
-                               val.set_object (property_object);
+
+                               try {
+                                       property_object = Serialization.deserialize_object (prop_elem_child);
+                                       val.set_object (property_object);
+                                       transformed = true;
+                               } catch (GXml.SerializationError e) {
+                                       // We don't want this one caught by deserialize_object, or we'd have 
a cascading error message.  Hmm, not so bad if it does, though.
+                                       e.message += "\nXML [%s]".printf (prop_elem.to_string ());
+                                       throw e;
+                               }
+                       }
+
+                       if (transformed == false) {
+                               throw new SerializationError.UNSUPPORTED_TYPE ("Failed to transform property 
from string to type.");
                        }
                }
 
-               /**
-                * FIXME: DON'T USE CACHE. SERIALIZE OVER NEW OBJECTS OR OVERWRITE PROPERTIES.
-                *       When serialize a set of objects, you can add Node Elements <Object>
-                *       as many as objects you have serialized to the XML Document. On
-                *       deserialization, you must create a new GObject, on the fly, for each
-                *       <Object> tag found in the file.
-                *
+               /*
                 * This table is used while deserializing objects to avoid
                 * creating duplicate objects when we encounter multiple
                 * references to a single serialized object.
                 *
                 * TODO: one problem, if you deserialize two XML structures,
                 * some differing objects might have the same OID :( Need to
-                * find make it more unique than just the memory address.  SEE ABOVE!!!!*/
+                * find make it more unique than just the memory address. */
                private static HashTable<string,Object> deserialize_cache = null;
                private static HashTable<string,GXml.Node> serialize_cache = null;
                // public so that tests can call it
@@ -352,27 +385,10 @@ namespace GXml {
                 * to the system deserializing them or a
                 * { link GXml.SerializationError} will result.
                 *
-                * @type object type to deserialize
-                * @doc a { link GXml.Document} to deseralize from
+                * @param doc { link GXml.Document} representing a { link GLib.Object}
                 * @return the deserialized { link GLib.Object}
                 */
-               public static GLib.Object deserialize_object (Type type, GXml.Document doc) throws GLib.Error
-               {
-                       if (type.is_a (typeof (Serializable))) {
-                               Object object = Object.new (type);
-                               ((Serializable) object).deserialize (doc);
-                               return object;
-                       }
-                       return deserialize_object_from_node (doc.document_element);
-               }
-
-               /**
-                * This function must assume deserialize over non-Serializable objects
-                * because Serializable have its own method serialize/deserialize
-                */
-               internal static GLib.Object? deserialize_object_from_node (GXml.Node obj_node) 
-                                                                         throws GLib.Error
-               {
+               public static GLib.Object deserialize_object (GXml.Node node) throws SerializationError {
                        Element obj_elem;
                        string otype;
                        string oid;
@@ -380,10 +396,14 @@ namespace GXml {
                        Object obj;
                        unowned ObjectClass obj_class;
                        ParamSpec[] specs;
+                       Serializable serializable = null;
 
-                       obj_elem = (Element)obj_node;
+                       if (node.get_type ().is_a (typeof (GXml.Document))) {
+                               obj_elem = (node as GXml.Document).document_element as GXml.Element;
+                       } else {
+                               obj_elem = node as GXml.Element;
+                       }
 
-                       // FIXME: Remove cache.
                        // If the object has been deserialised before, get it from cache
                        oid = obj_elem.get_attribute ("oid");
                        Serialization.init_caches ();
@@ -396,13 +416,7 @@ namespace GXml {
                        otype = obj_elem.get_attribute ("otype");
                        type = Type.from_name (otype);
                        if (type == 0) {
-                               throw new SerializationError.UNKNOWN_TYPE ("Deserializing unknown GType '%s' 
objects is unsupported", otype);
-                       }
-                       
-                       if (type.is_a (typeof (Serializable))) {
-                               obj = Object.new (type);
-                               ((Serializable) obj).deserialize (obj_node);
-                               return obj;
+                               throw new SerializationError.UNKNOWN_TYPE ("Deserializing object claims 
unknown type '%s'", otype);
                        }
 
                        // Get the list of properties as ParamSpecs
@@ -411,29 +425,177 @@ namespace GXml {
 
                        // Set it as the last possible action, so that invalid objects won't end up getting 
stored // Changed our mind, for deserializing ObjectRefs
                        Serialization.deserialize_cache.set (oid, obj);
-                       specs = obj_class.list_properties ();
+
+                       if (type.is_a (typeof (Serializable))) {
+                               serializable = (Serializable)obj;
+                       }
+
+                       if (serializable != null) {
+                               specs = serializable.list_properties ();
+                       } else {
+                               specs = obj_class.list_properties ();
+                       }
+
+                       SerializationError err = null;
 
                        foreach (Node child_node in obj_elem.child_nodes) {
                                if (child_node.node_name == "Property") {
                                        Element prop_elem;
                                        string pname;
                                        Value val;
+                                       //string ptype;
 
                                        prop_elem = (Element)child_node;
                                        pname = prop_elem.get_attribute ("pname");
+                                       //ptype = prop_elem.get_attribute ("ptype"); // optional
+
                                        // Check name and type for property
                                        ParamSpec? spec = null;
-                                       spec = obj_class.find_property (pname);
+                                       if (serializable != null) {
+                                               spec = serializable.find_property (pname);
+                                       } else {
+                                               spec = obj_class.find_property (pname);
+                                       }
 
                                        if (spec == null) {
-                                               throw new SerializationError.UNKNOWN_PROPERTY ("Unknown 
property '%s' found, for object type '%s'-->XML: [%s]", pname, otype, obj_elem.to_string ());
-                                               return null;
+                                               err = new SerializationError.UNKNOWN_PROPERTY ("Deserializing 
object of type '%s' claimed unknown property named '%s'\nXML [%s]", otype, pname, obj_elem.to_string ());
+                                               break;
+                                       }
+
+                                       try {
+                                               bool serialized = false;
+
+                                               if (serializable != null) {
+                                                       serialized = serializable.deserialize_property 
(spec.name, /* out val, */ spec, prop_elem); // TODO: consider rearranging these or the ones in Serializer to 
match
+                                               }
+                                               if (!serialized) {
+                                                       Serialization.deserialize_property (spec, prop_elem, 
out val);
+                                                       if (serializable != null) {
+                                                               serializable.set_property (spec, val);
+                                                       } else {
+                                                               obj.set_property (pname, val);
+                                                       }
+                                                       /* TODO: should we make a note that for implementing 
{get,set}_property in
+                                                          the interface, they should specify override (in 
Vala)?  What about in C?
+                                                          Need to test which one gets called in which 
situations (yeah, already read
+                                                          the tutorial) */
+                                               }
+                                       } catch (SerializationError.UNSUPPORTED_TYPE e) {
+                                               err = new SerializationError.UNSUPPORTED_TYPE ("Cannot 
deserialize object '%s's property '%s' with type '%s/%s': %s\nXML [%s]", otype, spec.name, 
spec.value_type.name (), spec.value_type.to_string (), e.message, obj_elem.to_string ());
+                                               break;
                                        }
-                                       Serialization.deserialize_property (spec, prop_elem, out val);
-                                       obj.set_property (pname, val);
                                }
                        }
+
+                       // TODO: should make a test to ensure this works
+                       if (err != null) {
+                               Serialization.deserialize_cache.remove (oid);
+                               throw err;
+                       }
+
                        return obj;
                }
+
+               /* TODO:
+                * - can't seem to pass delegates on struct methods to another function :(
+                * - no easy string_to_gvalue method in GValue :(
+                */
+
+               /**
+                * Transforms a string into another type hosted by { link GLib.Value}.
+                *
+                * A utility function that handles converting a string
+                * representation of a value into the type specified by the
+                * supplied #GValue dest.  A #GXmlSerializationError will be
+                * set if the string cannot be parsed into the desired type.
+                *
+                * @param str the string to transform into the given #GValue object
+                * @param dest the #GValue out parameter that will contain the parsed value from the string
+                * @return `true` if parsing succeeded, otherwise `false`
+                */
+               /*
+                * @todo: what do functions written in Vala return in C when
+                * they throw an exception?  NULL/0/FALSE?
+                */
+               public static bool string_to_gvalue (string str, ref GLib.Value dest) throws 
SerializationError {
+                       Type t = dest.type ();
+                       GLib.Value dest2 = Value (t);
+                       bool ret = false;
+
+                       if (t == typeof (int64)) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_int64 (val);
+                               }
+                       } else if (t == typeof (int)) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_int ((int)val);
+                               }
+                       } else if (t == typeof (long)) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_long ((long)val);
+                               }
+                       } else if (t == typeof (uint)) {
+                               uint64 val;
+                               if (ret = uint64.try_parse (str, out val)) {
+                                       dest2.set_uint ((uint)val);
+                               }
+                       } else if (t == typeof (ulong)) {
+                               uint64 val;
+                               if (ret = uint64.try_parse (str, out val)) {
+                                       dest2.set_ulong ((ulong)val);
+                               }
+                       } else if ((int)t == 20) { // gboolean
+                               bool val = (str == "TRUE");
+                               dest2.set_boolean (val); // TODO: huh, investigate why the type is gboolean 
and not bool coming out but is going in
+                               ret = true;
+                       } else if (t == typeof (bool)) {
+                               bool val;
+                               if (ret = bool.try_parse (str, out val)) {
+                                       dest2.set_boolean (val);
+                               }
+                       } else if (t == typeof (float)) {
+                               double val;
+                               if (ret = double.try_parse (str, out val)) {
+                                       dest2.set_float ((float)val);
+                               }
+                       } else if (t == typeof (double)) {
+                               double val;
+                               if (ret = double.try_parse (str, out val)) {
+                                       dest2.set_double (val);
+                               }
+                       } else if (t == typeof (string)) {
+                               dest2.set_string (str);
+                               ret = true;
+                       } else if (t == typeof (char)) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_schar ((int8)val);
+                               }
+                       } else if (t == typeof (uchar)) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_uchar ((uchar)val);
+                               }
+                       } else if (t == Type.BOXED) {
+                       } else if (t.is_enum ()) {
+                               int64 val;
+                               if (ret = int64.try_parse (str, out val)) {
+                                       dest2.set_enum ((int)val);
+                               }
+                       } else if (t.is_flags ()) {
+                       } else if (t.is_object ()) {
+                       } else {
+                       }
+
+                       if (ret == true) {
+                               dest = dest2;
+                               return true;
+                       } else {
+                               throw new SerializationError.UNSUPPORTED_TYPE ("%s/%s", t.name (), 
t.to_string ());
+                       }
+               }
        }
 }
diff --git a/gxml/Enumeration.vala b/gxml/xom/Enumeration.vala
similarity index 99%
rename from gxml/Enumeration.vala
rename to gxml/xom/Enumeration.vala
index b86f957..d375b60 100644
--- a/gxml/Enumeration.vala
+++ b/gxml/xom/Enumeration.vala
@@ -22,7 +22,7 @@
 
 using GXml;
 
-namespace GXml {
+namespace GXml.Xom {
        public class Enumeration
        {
                /**
diff --git a/gxml/SerializableContainer.vala b/gxml/xom/SerializableContainer.vala
similarity index 88%
rename from gxml/SerializableContainer.vala
rename to gxml/xom/SerializableContainer.vala
index f17dc7a..1e97fd7 100644
--- a/gxml/SerializableContainer.vala
+++ b/gxml/xom/SerializableContainer.vala
@@ -23,7 +23,7 @@
  * Any class having a collection managed list of nodes must implement this
  * abstract class.
  */
-public abstract class GXml.SerializableContainer : SerializableObjectModel
+public abstract class GXml.Xom.SerializableContainer : SerializableObjectModel
 {
   /* Xom interface properties */
   public abstract void init_containers ();
@@ -32,7 +32,7 @@ public abstract class GXml.SerializableContainer : SerializableObjectModel
 /**
  * Fake interface to be implemented by any collection.
  */
-public interface GXml.SerializableCollection : Object, Serializable
+public interface GXml.Xom.SerializableCollection : Object, Serializable
 {
   public virtual bool is_collection () { return true; }
 }
diff --git a/gxml/SerializableGeeArrayList.vala b/gxml/xom/SerializableGeeArrayList.vala
similarity index 97%
rename from gxml/SerializableGeeArrayList.vala
rename to gxml/xom/SerializableGeeArrayList.vala
index 4ca42a6..da2593d 100644
--- a/gxml/SerializableGeeArrayList.vala
+++ b/gxml/xom/SerializableGeeArrayList.vala
@@ -22,7 +22,7 @@
 using GXml;
 using Gee;
 
-public class GXml.SerializableArrayList<G> : Gee.ArrayList<G>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableArrayList<G> : Gee.ArrayList<G>, Serializable, SerializableCollection
 {
   protected ParamSpec[] properties { get; set; }
   public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableGeeDualKeyMap.vala b/gxml/xom/SerializableGeeDualKeyMap.vala
similarity index 98%
rename from gxml/SerializableGeeDualKeyMap.vala
rename to gxml/xom/SerializableGeeDualKeyMap.vala
index 667bdfe..99d9965 100644
--- a/gxml/SerializableGeeDualKeyMap.vala
+++ b/gxml/xom/SerializableGeeDualKeyMap.vala
@@ -22,7 +22,7 @@
 using GXml;
 using Gee;
 
-public class GXml.SerializableDualKeyMap<P,S,V> : Object, Serializable, SerializableCollection
+public class GXml.Xom.SerializableDualKeyMap<P,S,V> : Object, Serializable, SerializableCollection
 {
   protected Gee.HashMultiMap<P,HashMap<S,V>> storage;
 
diff --git a/gxml/SerializableGeeHashMap.vala b/gxml/xom/SerializableGeeHashMap.vala
similarity index 97%
rename from gxml/SerializableGeeHashMap.vala
rename to gxml/xom/SerializableGeeHashMap.vala
index a7ce625..b1b290c 100644
--- a/gxml/SerializableGeeHashMap.vala
+++ b/gxml/xom/SerializableGeeHashMap.vala
@@ -21,7 +21,7 @@
  */
 using GXml;
 
-public class GXml.SerializableHashMap<K,V> : Gee.HashMap<K,V>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableHashMap<K,V> : Gee.HashMap<K,V>, Serializable, SerializableCollection
 {
   protected ParamSpec[] properties { get; set; }
   public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableGeeTreeMap.vala b/gxml/xom/SerializableGeeTreeMap.vala
similarity index 97%
rename from gxml/SerializableGeeTreeMap.vala
rename to gxml/xom/SerializableGeeTreeMap.vala
index 4f3efd2..2f5d409 100644
--- a/gxml/SerializableGeeTreeMap.vala
+++ b/gxml/xom/SerializableGeeTreeMap.vala
@@ -21,7 +21,7 @@
  */
 using GXml;
 
-public class GXml.SerializableTreeMap<K,V> : Gee.TreeMap<K,V>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableTreeMap<K,V> : Gee.TreeMap<K,V>, Serializable, SerializableCollection
 {
   protected ParamSpec[] properties { get; set; }
   public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableJson.vala b/gxml/xom/SerializableJson.vala
similarity index 99%
rename from gxml/SerializableJson.vala
rename to gxml/xom/SerializableJson.vala
index 376776a..cf0ee3e 100644
--- a/gxml/SerializableJson.vala
+++ b/gxml/xom/SerializableJson.vala
@@ -60,7 +60,7 @@
  * serialization themselves, including non-public properties or
  * data types not automatically supported by { link GXml.Serialization}.
  */
-public class GXml.SerializableJson : GLib.Object, Serializable
+public class GXml.Xom.SerializableJson : GLib.Object, Serializable
 {
   /* Serializable Interface properties */
   protected ParamSpec[] properties { get; set; }
diff --git a/gxml/SerializableMapDualKey.vala b/gxml/xom/SerializableMapDualKey.vala
similarity index 94%
rename from gxml/SerializableMapDualKey.vala
rename to gxml/xom/SerializableMapDualKey.vala
index 5bfbf94..93b30c3 100644
--- a/gxml/SerializableMapDualKey.vala
+++ b/gxml/xom/SerializableMapDualKey.vala
@@ -20,7 +20,7 @@
  *      Daniel Espinosa <esodan gmail com>
  */
 using GXml;
-public interface GXml.SerializableMapDualKey<P,S> : Object
+public interface GXml.Xom.SerializableMapDualKey<P,S> : Object
 {
   public abstract P get_map_primary_key  ();
   public abstract S get_map_secondary_key ();
diff --git a/gxml/SerializableMapKey.vala b/gxml/xom/SerializableMapKey.vala
similarity index 94%
rename from gxml/SerializableMapKey.vala
rename to gxml/xom/SerializableMapKey.vala
index 944b1b0..a51403a 100644
--- a/gxml/SerializableMapKey.vala
+++ b/gxml/xom/SerializableMapKey.vala
@@ -21,7 +21,7 @@
  */
 using GXml;
 
-public interface GXml.SerializableMapKey<K> : Object
+public interface GXml.Xom.SerializableMapKey<K> : Object
 {
   public abstract K get_map_key ();
 }
diff --git a/gxml/xom/SerializableObjectModel.vala b/gxml/xom/SerializableObjectModel.vala
new file mode 100644
index 0000000..c3feb0e
--- /dev/null
+++ b/gxml/xom/SerializableObjectModel.vala
@@ -0,0 +1,383 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
+/* ObjectModel.vala
+ *
+ * Copyright (C) 2013, 2014  Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Daniel Espinosa <esodan gmail com>
+ */
+
+namespace GXml.Xom {
+    public abstract class SerializableObjectModel : Object, GXml.Serializable, Serializable
+    {
+        /* Serializable interface properties */
+        protected ParamSpec[] properties { get; set; }
+        public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
+        public string? serialized_xml_node_value { get; protected set; default=null; }
+        public virtual bool get_enable_unknown_serializable_property () { return false; }
+        public GLib.HashTable<string,GXml.Node> unknown_serializable_property { get; protected set; }
+
+        public virtual bool serialize_use_xml_node_value () { return false; }
+        public virtual bool property_use_nick () { return false; }
+
+        public virtual string node_name ()
+        {
+            return default_node_name ();
+        }
+        public string default_node_name ()
+        {
+            return get_type().name().down();
+        }
+
+        public virtual GLib.ParamSpec? find_property_spec (string property_name)
+        {
+            return default_find_property_spec (property_name);
+        }
+
+        public virtual void init_properties ()
+        {
+            default_init_properties ();
+        }
+
+        public virtual GLib.ParamSpec[] list_serializable_properties ()
+        {
+            return default_list_serializable_properties ();
+        }
+
+        public virtual void get_property_value (GLib.ParamSpec spec, ref Value val)
+        {
+            default_get_property_value (spec, ref val);
+        }
+
+        public virtual void set_property_value (GLib.ParamSpec spec, GLib.Value val)
+        {
+            default_set_property_value (spec, val);
+        }
+
+        public virtual bool transform_from_string (string str, ref GLib.Value dest)
+        {
+            return false;
+        }
+
+        public virtual bool transform_to_string (GLib.Value val, ref string str)
+        {
+            return false;
+        }
+
+        public virtual GXml.Node? serialize (GXml.Node node)
+        throws GLib.Error
+        requires (node_name () != null)
+        requires (node is Document || node is Element)
+        {
+            return default_serialize (node);
+        }
+
+        public GXml.Node? default_serialize (GXml.Node node) throws GLib.Error
+        {
+#if DEBUG
+            stdout.printf (@"$(get_type ().name ()): Serializing on node: $(node.node_name)\n");
+#endif
+            Document doc;
+            if (node is Document)
+                doc = (Document) node;
+            else
+                doc = node.owner_document;
+            var element = doc.create_element (node_name ());
+            foreach (ParamSpec spec in list_serializable_properties ()) {
+                serialize_property (element, spec);
+            }
+            if (get_enable_unknown_serializable_property ()) {
+                foreach (Node n in unknown_serializable_property.get_values ()) {
+                    if (n is Element) {
+                        var e = (Node) doc.create_element (n.node_name);
+                        n.copy (ref e, true);
+                        element.append_child (e);
+                    }
+                    if (n is Attr) {
+                        element.set_attribute (n.node_name, n.node_value);
+                        var a = (Node) element.get_attribute_node (n.node_name);
+                        n.copy (ref a);
+                    }
+                    if (n is Text) {
+                        var tnode = doc.create_text_node (n.node_value);
+                        element.append_child (tnode);
+                    }
+                }
+            }
+            // Setting element content
+            if (serialize_use_xml_node_value ()) {
+                // Set un empty string if no value is set for node contents
+                string t = "";
+                if (serialized_xml_node_value != null)
+                    t = serialized_xml_node_value;
+                var tn = doc.create_text_node (t);
+#if DEBUG
+                stdout.printf (@"SETTING CONTENT FOR: $(get_type ().name ()): $(element.node_name): content 
'$t'\n");
+#endif
+                element.append_child (tn);
+            }
+
+            node.append_child (element);
+            return element;
+        }
+
+        public virtual GXml.Node? serialize_property (GXml.Element element,
+                                                      GLib.ParamSpec prop)
+        throws GLib.Error
+        {
+            return default_serialize_property (element, prop);
+        }
+        public GXml.Node? default_serialize_property (GXml.Element element,
+                                                      GLib.ParamSpec prop)
+        throws GLib.Error
+        {
+            if (prop.value_type.is_a (typeof (Serializable))) 
+            {
+                var v = Value (typeof (Object));
+                get_property (prop.name, ref v);
+                var obj = (Serializable) v.get_object ();
+                if (obj != null)
+                    return obj.serialize (element);
+            }
+            Value oval;
+            if (prop.value_type.is_a (Type.ENUM))
+                oval = Value (typeof (int));
+            else
+                oval = Value (prop.value_type);
+            get_property (prop.name, ref oval);
+            string val = "";
+            if (prop.value_type.is_a (Type.ENUM)) {
+                try {
+                    val = Enumeration.get_nick_camelcase (prop.value_type, oval.get_int ());
+                } catch (EnumerationError e) { val = null; }
+            }
+            else
+            {
+                if (!transform_to_string (oval, ref val)) {
+                    if (Value.type_transformable (prop.value_type, typeof (string)))
+                    {
+                        Value rval = Value (typeof (string));
+                        oval.transform (ref rval);
+                        val = rval.dup_string ();
+                    }
+                    else {
+                        Node node = null;
+                        this.serialize_unknown_property (element, prop, out node);
+                        return node;
+                    }
+                }
+            }
+            string attr_name;
+            if (property_use_nick () &&
+                prop.get_nick () != null &&
+                prop.get_nick () != "")
+                attr_name = prop.get_nick ();
+            else
+                attr_name = prop.get_name ();
+            var attr = element.get_attribute_node (attr_name);
+            if (attr == null) {
+                if (val != null)
+                    element.set_attribute (attr_name, val);
+            }
+            else
+                attr.value = val;
+            return (Node) attr;
+        }
+
+        public virtual GXml.Node? deserialize (GXml.Node node)
+        throws GLib.Error
+        requires (node_name () != null)
+        {
+            return default_deserialize (node);
+        }
+        public GXml.Node? default_deserialize (GXml.Node node)
+        throws GLib.Error
+        {
+            Document doc;
+            if (node is Document) {
+                doc = (Document) node;
+                return_val_if_fail (doc.document_element != null, null);
+            }
+            else
+                doc = node.owner_document;
+            Element element;
+            if (node is Element)
+                element = (Element) node;
+            else
+                element = (Element) doc.document_element;
+            return_val_if_fail (element != null, null);
+            if (node_name () == null) {
+                message (@"WARNING: Object type '$(get_type ().name ())' have no Node Name defined");
+                return null;
+            }
+#if DEBUG
+            if (element.node_name.down () != node_name ().down ()) {
+                GLib.warning (@"Actual node's name is '$(element.node_name.down ())' expected '$(node_name 
().down ())'");
+            }
+            stdout.printf (@"Deserialize Node: $(element.node_name)\n");
+            stdout.printf (@"Node is: $(element)\n\n");
+            stdout.printf (@"Attributes in Node: $(element.node_name)\n");
+#endif
+            foreach (Attr attr in element.attributes.get_values ())
+            {
+                deserialize_property (attr);
+            }
+#if DEBUG
+            stdout.printf (@"Elements Nodes in Node: $(element.node_name)\n");
+#endif
+            if (element.has_child_nodes ())
+            {
+                if (get_type ().is_a (typeof (SerializableContainer)))
+                {
+//        stdout.printf (@"This is a Container: found a: $(get_type ().name ())\n");
+                    ((SerializableContainer) this).init_containers ();
+                }
+                var cnodes = new Gee.HashMap<string,ParamSpec> ();
+                foreach (ParamSpec spec in list_serializable_properties ())
+                {
+                    if (spec.value_type.is_a (typeof (Serializable)))
+                    {
+                        if (spec.value_type.is_a (typeof (SerializableCollection)))
+                        {
+                            Value vo = Value (spec.value_type);
+                            get_property (spec.name, ref vo);
+                            var objv = vo.get_object ();
+                            if (objv != null) {
+                                ((Serializable) objv).deserialize (element);
+                                cnodes  set (((Serializable) objv).node_name (), spec);
+//                stdout.printf (@"Added Key for container node as: $(((Serializable) objv).node_name 
())\n");
+                            }
+                        }
+                    }
+                }
+                foreach (Node n in element.child_nodes)
+                {
+                    if (n is Text) {
+                        if (serialize_use_xml_node_value ()) {
+                            serialized_xml_node_value = n.node_value;
+#if DEBUG
+                            stdout.printf (@"$(get_type ().name ()): NODE '$(element.node_name)' CONTENT 
'$(n.node_value)'\n");
+#endif
+                        } else {
+                            if (get_enable_unknown_serializable_property ()) {
+                                if (n.node_value._chomp () == n.node_value && n.node_value != "")
+                                    unknown_serializable_property.set (n.node_name, n);
+                            }
+                        }
+                    }
+                    if (n is Element  && !cnodes.has_key (n.node_name)) {
+#if DEBUG
+                        stdout.printf (@"$(get_type ().name ()): DESERIALIZING ELEMENT '$(n.node_name)'\n");
+#endif
+                        deserialize_property (n);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public virtual bool deserialize_property (GXml.Node property_node)
+        throws GLib.Error
+        {
+            return default_deserialize_property (property_node);
+        }
+        public bool default_deserialize_property (GXml.Node property_node)
+        throws GLib.Error
+        {
+#if DEBUG
+            stdout.printf (@"Deserialize Property Node: $(property_node.node_name)\n");
+#endif
+            bool ret = false;
+            var prop = find_property_spec (property_node.node_name);
+            if (prop == null) {
+                // FIXME: Event emit
+                if (get_enable_unknown_serializable_property ()) {
+//        stdout.printf (@"Adding node $(property_node.node_name) to $(get_type ().name ())\n");
+                    unknown_serializable_property.set (property_node.node_name, property_node);
+                }
+                return true;
+            }
+            if (prop.value_type.is_a (typeof (Serializable)))
+            {
+                Value vobj = Value (typeof(Object));
+                get_property (prop.name, ref vobj);
+                if (vobj.get_object () == null) {
+                    var obj = Object.new  (prop.value_type);
+                    ((Serializable) obj).deserialize (property_node);
+                    set_property (prop.name, obj);
+                }
+                else
+                    ((Serializable) vobj.get_object ()).deserialize (property_node);
+                return true;
+            }
+            else {
+                Value val;
+                if (prop.value_type == Type.ENUM)
+                    val = Value (typeof (int));
+                else
+                    val = Value (prop.value_type);
+                if (property_node is GXml.Attr)
+                {
+                    if (prop.value_type.is_a (Type.ENUM)) {
+                        EnumValue env;
+                        try {
+                            env = Enumeration.parse (prop.value_type, property_node.node_value);
+                            val.set_enum (env.value);
+                        }
+                        catch (EnumerationError e) {}
+                    }
+                    else {
+                        if (!transform_from_string (property_node.node_value, ref val)) {
+                            Value ptmp = Value (typeof (string));
+                            ptmp.set_string (property_node.node_value);
+                            if (Value.type_transformable (typeof (string), prop.value_type))
+                                ret = ptmp.transform (ref val);
+                            else
+                                ret = string_to_gvalue (property_node.node_value, ref val);
+                        }
+                    }
+                    set_property (prop.name, val);
+                    return ret;
+                }
+            }
+            // Attribute can't be deseralized with standard methods. Up to the implementor.
+            this.deserialize_unknown_property (property_node, prop);
+            return true;
+        }
+        public abstract string to_string ();
+
+        public static bool equals (SerializableObjectModel a, SerializableObjectModel b)
+        {
+            if (b.get_type () == a.get_type ()) {
+                var alp = ((Serializable)a).list_serializable_properties ();
+                bool ret = true;
+                foreach (ParamSpec p in alp) {
+                    var bp = ((Serializable)b).find_property_spec (p.name);
+                    if (bp != null) {
+                        Value apval = Value (p.value_type);
+                        ((Serializable)a).get_property_value (p, ref apval);
+                        Value bpval = Value (bp.value_type);;
+                        ((Serializable)b).get_property_value (bp, ref bpval);
+                        if ( apval != bpval)
+                            ret = false;
+                    }
+                }
+                return ret;
+            }
+            return false;
+        }
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]