[gxml/serialization: 6/10] Fixing Serializable.serialize() and deserialize() on conplex Element nodes



commit 1f11a5b6cf74dad097346fa2ca03db55983dc88a
Author: Daniel Espinosa <esodan gmail com>
Date:   Tue Jul 23 16:24:22 2013 -0500

    Fixing Serializable.serialize() and deserialize() on conplex Element nodes

 gxml/NodeList.vala                |   11 +-
 gxml/Serializable.vala            |  192 ++++++++++++++++++-------------------
 gxml/SerializableObjectModel.vala |    2 +-
 test/SerializableTest.vala        |   19 ++--
 4 files changed, 107 insertions(+), 117 deletions(-)
---
diff --git a/gxml/NodeList.vala b/gxml/NodeList.vala
index 13a993d..c756de6 100644
--- a/gxml/NodeList.vala
+++ b/gxml/NodeList.vala
@@ -32,9 +32,8 @@ namespace GXml {
         * { link GXml.Element.get_elements_by_tag_name}.
         */
        public interface NodeList : Gee.Iterable<DomNode> {
-               public abstract ulong length {
-                       get; private set;
-               }
+
+               public abstract ulong length { get; private set; }
                /* NOTE:
                 * children should define constructors like:
                 *     internal NodeList (Xml.Node* head, Document owner);
@@ -631,8 +630,10 @@ namespace GXml {
                        }
 
                        protected override void advance () {
-                               this.cur = this.next_node;
-                               this.next_node = cur->next;
+                               if (!is_empty ()) {
+                                       this.cur = this.next_node;
+                                       this.next_node = cur->next;
+                               }
                        }
                }
        }
diff --git a/gxml/Serializable.vala b/gxml/Serializable.vala
index 777f15c..be0dbe2 100644
--- a/gxml/Serializable.vala
+++ b/gxml/Serializable.vala
@@ -92,19 +92,19 @@ namespace GXml {
                 *
                 * This property must be ignored on serialisation.
                 */
-               public abstract Element                           serialized_xml_node { get; protected set; }
+               public abstract Element  serialized_xml_node { get; protected set; default = null; }
 
                /**
                 * Used by to add properties and values to DomNode.
                 *
                 * This property must be ignored on serialisation.
                 */
-               public abstract string  serialized_xml_node_value { get; protected set; default = null; }
+               public abstract string?  serialized_xml_node_value { get; protected set; default = null; }
 
                /**
                 * Serialize this object.
                 *
-                * @doc an GXml.Document object to serialise to 
+                * @doc an { link GXml.Document} object to serialise to 
                 */
                public virtual DomNode? serialize (DomNode node) throws DomError
                {
@@ -113,27 +113,78 @@ namespace GXml {
                                doc = (Document) node;
                        else
                                doc = node.owner_document;
-                       if (serialized_xml_node == null)
-                               serialized_xml_node = doc.create_element (this.get_type ().name ());
+                       GLib.message ("Serialing on ..." + node.node_name);
+                       var element = doc.create_element (this.get_type().name());
                        foreach (ParamSpec spec in list_serializable_properties ()) {
-                               serialize_property (spec);
+                               GLib.message ("Property to Serialize: " + spec.name);
+                               serialize_property (element, spec);
                        }
-                       /* FIXME: Save unknown nodes */
-//                     if (unknown_serializable_property.size >= 1) {
-//                             foreach (DomNode node in unknown_serializable_property.get_values ()) {
-//                                     if (node is Attr) {
-//                                             var att = (Attr) node;
-//                                             serialized_xml_node.set_attribute (att.name, )
-//                                     }
-//                             }
-//                             serialized_xml_node.append_child ()
-//                     }
                        if (serialized_xml_node_value != null)
                                serialized_xml_node.content = serialized_xml_node_value;
-                       node.append_child (serialized_xml_node);
+                       node.append_child (element);
+                       GLib.message ("Added a new top node" + serialized_xml_node.node_name);
                        return serialized_xml_node;
                }
 
+               /**
+                * 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.DomNode} that encapsulates the property.
+                * { link GXml.Serialization} will embed the { link GXml.DomNode} into
+                * a "Property" { link GXml.Element}, so the { link GXml.DomNode}
+                * 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 itsel.
+                *
+                * @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.DomNode} should belong to
+                * @return a new { link GXml.DomNode}, or `null`
+                */
+               public virtual GXml.DomNode? serialize_property (Element element,
+                                                                GLib.ParamSpec prop)
+                                                                throws DomError
+               {
+                       if (prop.value_type.is_a (typeof (Serializable))) 
+                       {
+                               GLib.message (@"$(prop.name) Is a Serializable");
+                               var v = Value (typeof (Object));
+                               get_property (prop.name, ref v);
+                               var obj = (Serializable) v.get_object ();
+                               return obj.serialize (element);
+                       }
+                       Value oval = Value (prop.value_type);
+                       get_property (prop.name, ref oval);
+                       string val = "";
+                       if (Value.type_transformable (prop.value_type, typeof (string)))
+                       {
+                               Value rval = Value (typeof (string));
+                               oval.transform (ref rval);
+                               val = rval.dup_string ();
+                       }
+                       string attr_name = prop.name.down ();
+                       var attr = element.get_attribute_node (attr_name);
+                       if (attr == null) {
+                               GLib.message (@"New Attr to add... $(attr_name)");
+                               element.set_attribute (attr_name, val);
+                       }
+                       else
+                               attr.value = val;
+                       return (DomNode) attr;
+               }
+
+               /**
+                * Deserialize this object.
+                *
+                * @node { link GXml.DomNode} used to deserialize from.
+                */
                public virtual DomNode? deserialize (DomNode node)
                                                     throws DomError
                {
@@ -177,24 +228,11 @@ namespace GXml {
                 * 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.DomNode} 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 (GXml.DomNode property_node)
                                                          throws Error
                {
@@ -204,25 +242,33 @@ namespace GXml {
                                GLib.message ("Found Unknown property: " + property_node.node_name);
                                // FIXME: Event emit
                                unknown_serializable_property.set (property_node.node_name, property_node);
-                               return false;
+                               return true;
                        }
                        if (prop.value_type.is_a (typeof (Serializable)))
                        {
-                               GLib.message (@"$(prop.name): Is Serializable...");
-                               var obj = Object.new  (prop.value_type);
-                               ((Serializable) obj).deserialize (property_node);
-                               set_property (prop.name, obj);
+                               Value vobj = Value (typeof(Object));
+                               get_property (prop.name, ref vobj);
+                               if (vobj.get_object () == null) {
+                                       GLib.message (@"$(prop.name): Is Serializable...");
+                                       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;
                        }
-                       Value val = Value (prop.value_type);
-                       if (Value.type_transformable (typeof (DomNode), prop.value_type))
-                       {
-                               Value tmp = Value (typeof (DomNode));
-                               tmp.set_object (property_node);
-                               ret = tmp.transform (ref val);
-                       }
                        else {
-                               if (property_node is GXml.Attr && !ret)
+                               Value val = Value (prop.value_type);
+                               if (Value.type_transformable (typeof (DomNode), prop.value_type))
+                               {
+                                       Value tmp = Value (typeof (DomNode));
+                                       tmp.set_object (property_node);
+                                       ret = tmp.transform (ref val);
+                                       set_property (prop.name, val);
+                                       return ret;
+                               }
+                               if (property_node is GXml.Attr)
                                {
                                        Value ptmp = Value (typeof (string));
                                        ptmp.set_string (property_node.node_value);
@@ -230,65 +276,11 @@ namespace GXml {
                                                ret = ptmp.transform (ref val);
                                        else
                                                ret = string_to_gvalue (property_node.node_value, ref val);
+                                       set_property (prop.name, val);
+                                       return ret;
                                }
                        }
-                       if (ret) {
-                               set_property (prop.name, val);
-                       }
-                       return ret;
-               }
-
-               /**
-                * 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.DomNode} that encapsulates the property.
-                * { link GXml.Serialization} will embed the { link GXml.DomNode} into
-                * a "Property" { link GXml.Element}, so the { link GXml.DomNode}
-                * 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 itsel.
-                *
-                * @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.DomNode} should belong to
-                * @return a new { link GXml.DomNode}, or `null`
-                */
-               public virtual GXml.DomNode? serialize_property (GLib.ParamSpec spec)
-                                                                throws DomError
-               {
-                       var prop = find_property_spec (spec.name);
-                       if (prop == null) {
-                               GLib.warning ("No such property: " + spec.name);
-                               return null;
-                       }
-                       if (prop.value_type.is_a (typeof (Serializable))) {
-                               var v = Value (typeof (Object));
-                               get_property (spec.name, ref v);
-                               var obj = (Serializable) v.get_object ();
-                               var node = obj.serialize (serialized_xml_node);
-                               return node;
-                       }
-                       Value oval = Value (spec.value_type);
-                       get_property (spec.name, ref oval);
-                       string val = "";
-                       if (Value.type_transformable (spec.value_type, typeof (string)))
-                       {
-                               Value rval = Value (typeof (string));
-                               oval.transform (ref rval);
-                               val = rval.dup_string ();
-                       }
-                       string attr_name = spec.name;
-                       if (serializable_property_use_nick)
-                               attr_name = spec.get_nick ();
-                       serialized_xml_node.set_attribute (attr_name, val);
-                       return (DomNode) serialized_xml_node.get_attribute_node (attr_name);
+                       return false;
                }
 
                /*
diff --git a/gxml/SerializableObjectModel.vala b/gxml/SerializableObjectModel.vala
index cc3c7ea..366956b 100644
--- a/gxml/SerializableObjectModel.vala
+++ b/gxml/SerializableObjectModel.vala
@@ -26,7 +26,7 @@ public abstract class GXml.SerializableObjectModel : Object, Serializable
        public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
        public bool serializable_property_use_nick { get; set; }
        public GXml.Element serialized_xml_node { get; protected set; }
-       public string serialized_xml_node_value { get; protected set; default=null; }
+       public string? serialized_xml_node_value { get; protected set; default=null; }
        public GLib.HashTable<string,GXml.DomNode> unknown_serializable_property { get; protected set; }
 
        /* No serializable properties */
diff --git a/test/SerializableTest.vala b/test/SerializableTest.vala
index c6cce05..56aef30 100644
--- a/test/SerializableTest.vala
+++ b/test/SerializableTest.vala
@@ -31,7 +31,7 @@ public class SerializableTomato : GLib.Object, GXml.Serializable
        public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; private set; }
        public bool serializable_property_use_nick { get; set; }
        public GXml.Element serialized_xml_node { get; protected set; }
-       public string serialized_xml_node_value { get; protected set; }
+       public string? serialized_xml_node_value { get; protected set; }
        public GLib.HashTable<string,GXml.DomNode> unknown_serializable_property { get; private set; }
 
        public int weight;
@@ -69,7 +69,7 @@ public class SerializableCapsicum : GLib.Object, GXml.Serializable
        public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; private set; }
        public bool serializable_property_use_nick { get; set; }
        public GXml.Element serialized_xml_node { get; protected set; }
-       public string serialized_xml_node_value { get; protected set; }
+       public string? serialized_xml_node_value { get; protected set; }
        public GLib.HashTable<string,GXml.DomNode> unknown_serializable_property { get; private set; }
 
        public int weight;
@@ -95,16 +95,12 @@ public class SerializableCapsicum : GLib.Object, GXml.Serializable
                this.ratings = ratings;
        }
 
-       /* TODO: do we really need GLib.Value? or should we modify the object directly?
-          Want an example using GBoxed too
-          Perhaps these shouldn't be object methods, perhaps they should be static?
-          Can't have static methods in an interface :(, right? */
-       public bool deserialize_property (GLib.ParamSpec spec,
-                                         GXml.DomNode property_node)
+       public bool deserialize_property (GXml.DomNode property_node)
+                                         throws Error
        {
                GLib.Value outvalue = GLib.Value (typeof (int));
 
-               switch (spec.name) {
+               switch (property_node.node_name) {
                case "ratings":
                        this.ratings = new GLib.List<int> ();
                        foreach (GXml.DomNode rating in property_node.child_nodes) {
@@ -117,7 +113,8 @@ public class SerializableCapsicum : GLib.Object, GXml.Serializable
                        this.height = (int)outvalue.get_int64 () - 1;
                        return true;
                default:
-                       Test.message ("Wasn't expecting the SerializableCapsicum property '%s'", spec.name);
+                       Test.message (@"Wasn't expecting the SerializableCapsicum " + 
+                                     "property '$(property_node.node_name)'");
                        assert_not_reached ();
                }
 
@@ -163,7 +160,7 @@ public class SerializableBanana : GLib.Object, GXml.Serializable
        public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; private set; }
        public bool serializable_property_use_nick { get; set; }
        public GXml.Element serialized_xml_node { get; protected set; }
-       public string serialized_xml_node_value { get; protected set; }
+       public string? serialized_xml_node_value { get; protected set; }
        public GLib.HashTable<string,GXml.DomNode> unknown_serializable_property { get; private set; }
 
        private int private_field;


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