[gxml] Moved Xom/Json implementation to Xom library



commit 1f9d1bbc4d29b6cc1e5bffb453fff98b62283e84
Author: Daniel Espinosa <esodan gmail com>
Date:   Mon Apr 14 19:03:09 2014 -0500

    Moved Xom/Json implementation to Xom library
    
      Cleaned out GXml from any serialization framework.

 gxml/Document.vala                   |    4 +-
 gxml/Makefile.am                     |    5 +-
 gxml/Serializable.vala               |  567 ----------------------------------
 gxml/Serialization.vala              |   12 +-
 gxml/xom/Makefile.am                 |    7 +-
 gxml/{ => xom}/SerializableJson.vala |   15 +-
 gxml/xom/Serialization.vala          |  439 ++++++++++++++++++++++++++
 test/SerializableTest.vala           |   10 +-
 test/SerializationTest.vala          |   11 +-
 9 files changed, 472 insertions(+), 598 deletions(-)
---
diff --git a/gxml/Document.vala b/gxml/Document.vala
index 7ed2244..7a777e1 100644
--- a/gxml/Document.vala
+++ b/gxml/Document.vala
@@ -1,4 +1,4 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
 /* Document.vala
  *
  * Copyright (C) 2011-2013  Richard Schwarting <aquarichy gmail com>
@@ -1020,7 +1020,7 @@ namespace GXml {
                        return (xmldoc->children != null);
                }
 
-               internal unowned Node copy_node (Node foreign_node, bool deep = true) {
+               public unowned Node copy_node (Node foreign_node, bool deep = true) {
                        Xml.Node *our_copy_xml = ((BackedNode)foreign_node).node->doc_copy (this.xmldoc, deep 
? 1 : 0);
                        // TODO: do we need to append this to this.new_nodes?  Do we need to append the 
result to this.nodes_to_free?  Test memory implications
                        return this.lookup_node (our_copy_xml); // inducing a GXmlNode
diff --git a/gxml/Makefile.am b/gxml/Makefile.am
index ae2f5d7..ac68611 100644
--- a/gxml/Makefile.am
+++ b/gxml/Makefile.am
@@ -35,10 +35,7 @@ sources = \
        NodeType.vala \
        Notation.vala \
        ProcessingInstruction.vala \
-       Text.vala \
-       Serializable.vala \
-       SerializableJson.vala \
-       Serialization.vala
+       Text.vala
 
 
 ### General Compilation flags
diff --git a/gxml/Serialization.vala b/gxml/Serialization.vala
index f90ff54..3c3dc01 100644
--- a/gxml/Serialization.vala
+++ b/gxml/Serialization.vala
@@ -1,4 +1,4 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
 /* Serialization.vala
  *
  * Copyright (C) 2012-2013  Richard Schwarting <aquarichy gmail com>
@@ -27,7 +27,7 @@
 
 using GXml;
 
-namespace GXml {
+namespace Xom {
        private static void print_object_properties (GLib.Object obj) {
                ParamSpec[] properties;
                properties = obj.get_class ().list_properties ();
@@ -106,7 +106,7 @@ namespace GXml {
                {
                        Type type;
                        Value value;
-                       Node value_node;
+                       GXml.Node value_node;
                        Serializable serializable = null;
 
                        if (object.get_type ().is_a (typeof (Serializable))) {
@@ -174,7 +174,7 @@ namespace GXml {
                                                 on the interface 'GeeBidirSortedSet' */
                                        child_object = value.get_object ();
                                        Document value_doc = Serialization.serialize_object (child_object); 
// catch serialisation errors?
-
+                                       // TODO: Make copy_node public to allow others to use it
                                        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 ());
@@ -216,7 +216,7 @@ namespace GXml {
                        Element root;
                        ParamSpec[] prop_specs;
                        Element prop;
-                       Node value_prop = null;
+                       GXml.Node value_prop = null;
                        string oid;
 
                        Serialization.init_caches ();
@@ -413,7 +413,7 @@ namespace GXml {
                        Serialization.deserialize_cache.set (oid, obj);
                        specs = obj_class.list_properties ();
 
-                       foreach (Node child_node in obj_elem.child_nodes) {
+                       foreach (GXml.Node child_node in obj_elem.child_nodes) {
                                if (child_node.node_name == "Property") {
                                        Element prop_elem;
                                        string pname;
diff --git a/gxml/xom/Makefile.am b/gxml/xom/Makefile.am
index 1a31949..d239b86 100644
--- a/gxml/xom/Makefile.am
+++ b/gxml/xom/Makefile.am
@@ -21,7 +21,9 @@ sources = \
        SerializableGeeDualKeyMap.vala \
        SerializableMapDualKey.vala \
        SerializableGeeArrayList.vala \
-       SerializableContainer.vala
+       SerializableContainer.vala \
+       SerializableJson.vala \
+       Serialization.vala
 
 
 ### General Compilation flags
@@ -51,8 +53,7 @@ AM_VALAFLAGS = \
        --library=xom-0.4 \
        $(top_srcdir)/vapi/config.vapi \
        --vapidir=. \
-       --vapidir=$(top_srcdir)/vapi \
-       --vapidir=../gxml \
+       --vapidir=.. \
        --pkg gxml-0.4 \
        --pkg libxml-2.0 \
        --pkg gee-0.8 \
diff --git a/gxml/SerializableJson.vala b/gxml/xom/SerializableJson.vala
similarity index 95%
rename from gxml/SerializableJson.vala
rename to gxml/xom/SerializableJson.vala
index 376776a..e80eda6 100644
--- a/gxml/SerializableJson.vala
+++ b/gxml/xom/SerializableJson.vala
@@ -22,6 +22,7 @@
  *       Daniel Espinosa <esodan gmail com>
  */
 
+using GXml;
 
 /*
   Version 3: json-glib version
@@ -60,7 +61,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 Xom.SerializableJson : GLib.Object, Xom.Serializable
 {
   /* Serializable Interface properties */
   protected ParamSpec[] properties { get; set; }
@@ -115,7 +116,7 @@ public class GXml.SerializableJson : GLib.Object, Serializable
    * Is up to you to add convenient Element node to a Document, in order to be
    * used by serialize and add new <Object> tags per object to serialize.
    */
-  public Node? serialize (Node node) throws GLib.Error
+  public GXml.Node? serialize (GXml.Node node) throws GLib.Error
   {
     Document doc;
     Element root;
@@ -144,7 +145,7 @@ public class GXml.SerializableJson : GLib.Object, Serializable
   {
     Type type;
     Value val;
-    Node value_node = null;
+    GXml.Node value_node = null;
     Element prop_node;
 
     type = prop.value_type;
@@ -195,7 +196,9 @@ public class GXml.SerializableJson : GLib.Object, Serializable
       this.get_property_value (prop, ref val);
       child_object = val.get_object ();
       Document value_doc = Serialization.serialize_object (child_object);
-      value_node = doc.copy_node (value_doc.document_element);
+      value_node = doc.create_element ("fake");
+      value_doc.document_element.copy (ref value_node, true);
+      //value_node = doc.copy_node (value_doc.document_element);
       prop_node.append_child (value_node);
       return prop_node;
     }
@@ -204,7 +207,7 @@ public class GXml.SerializableJson : GLib.Object, Serializable
     return prop_node;
   }
 
-  public Node? deserialize (Node node) throws GLib.Error
+  public GXml.Node? deserialize (GXml.Node node) throws GLib.Error
   {
     Element obj_elem;
     ParamSpec[] specs;
@@ -218,7 +221,7 @@ public class GXml.SerializableJson : GLib.Object, Serializable
 
     specs = this.list_serializable_properties ();
 
-    foreach (Node child_node in obj_elem.child_nodes) {
+    foreach (GXml.Node child_node in obj_elem.child_nodes) {
       deserialize_property (child_node);
     }
     return obj_elem;
diff --git a/gxml/xom/Serialization.vala b/gxml/xom/Serialization.vala
new file mode 100644
index 0000000..db48ceb
--- /dev/null
+++ b/gxml/xom/Serialization.vala
@@ -0,0 +1,439 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
+/* Serialization.vala
+ *
+ * Copyright (C) 2012-2013  Richard Schwarting <aquarichy 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>
+ */
+
+/* TODO: so it seems we can get property information from GObjectClass
+   but that's about it.  Need to definitely use introspection for anything
+   tastier */
+/* TODO: document memory management for the C side */
+
+using GXml;
+
+namespace Xom {
+       private static void print_object_properties (GLib.Object obj) {
+               ParamSpec[] properties;
+               properties = obj.get_class ().list_properties ();
+               stdout.printf ("object has %d properties\n", properties.length);
+               foreach (ParamSpec prop_spec in properties) {
+                       stdout.printf ("---\n");
+                       stdout.printf ("name            %s\n", prop_spec.name);
+                       stdout.printf ("  value_type    %s\n", prop_spec.value_type.name ());
+                       stdout.printf ("  owner_type    %s\n", prop_spec.owner_type.name ());
+                       stdout.printf ("  get_name ()   %s\n", prop_spec.get_name ());
+                       stdout.printf ("  get_blurb ()  %s\n", prop_spec.get_blurb ());
+                       stdout.printf ("  get_nick ()   %s\n", prop_spec.get_nick ());
+               }
+       }
+
+       /**
+        * Errors from { link Serialization}.
+        */
+       public errordomain SerializationError {
+               /**
+                * An unknown { link GLib.Type} was encountered.
+                */
+               UNKNOWN_TYPE,
+               /**
+                * A property was described in XML that is not known { link GLib.Type}.
+                */
+               UNKNOWN_PROPERTY,
+               /**
+                * Serialization/Deserialization is unsupported for given object type
+                */
+               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
+       }
+
+       /**
+        * Serializes and deserializes { link GLib.Object}s to and from
+        * { link GXml.Node}.
+        *
+        * Serialization can automatically serialize a variety of public
+        * properties.  { link GLib.Object}s can also implement the
+        * { link GXml.Serializable} to partially or completely manage
+        * serialization themselves, including non-public properties or
+        * data types not automatically supported by { link GXml.Serialization}.
+        */
+       public class Serialization : GLib.Object {
+               private static void print_debug (GXml.Document doc, GLib.Object object) {
+                       stdout.printf ("Object XML\n---\n%s\n", doc.to_string ());
+
+                       stdout.printf ("object\n---\n");
+                       stdout.printf ("get_type (): %s\n", object.get_type ().name ());
+                       stdout.printf ("get_class ().get_type (): %s\n", object.get_class ().get_type ().name 
());
+                       Xom.print_object_properties (object);
+               }
+
+               /*
+                * This coordinates the automatic serialization of individual
+                * properties.  As of 0.2, it supports enums, anything that
+                * { 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
+               {
+                       Type type;
+                       Value value;
+                       GXml.Node value_node;
+                       Serializable serializable = null;
+
+                       if (object.get_type ().is_a (typeof (Serializable))) {
+                               serializable = (Serializable)object;
+                       }
+
+                       type = prop_spec.value_type;
+
+                       if (prop_spec.value_type.is_enum ()) {
+                               /* We're going to handle this simply by saving it
+                                  as an int.  If we save a string representation,
+                                  we can't easily convert it back to the number
+                                  in a generic fashion unless we can use GEnumClass,
+                                  but I can't figure out how to get that right now,
+                                  except from a GParamSpecEnum, but I don't know
+                                  how to get that, at least in Vala (e.g. is it
+                                  supposed to be as simple in C as casting the
+                                  GParamSpec for an enum to GParamSpecEnum (assuming
+                                  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);
+                               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);
+                               value_node = doc.create_text_node (value.get_string ());
+                       } else if (type == typeof (GLib.Type)) {
+                               value_node = doc.create_text_node (type.name ());
+/*
+                       } else if (type.is_a (typeof (Gee.Collection))) {
+                           // We need to be able to figure out
+                               // * what generics it has, and
+                               // * any parametres for delegates it might have used.
+                               GXml.print_object_properties (object);
+                               value_node = null;
+                       } else if (type == typeof (GLib.HashTable)) {
+
+                       } else if (type == typeof (Gee.List)) {
+                               // TODO: can we do a catch all for Gee.Collection and have <Collection /> ?
+                       } else if (type.is_a (typeof (Gee.TreeSet))) {
+                               object.get_property (prop_spec, ref value);
+                               doc.create_element ("Collection");
+                               foreach (Object member in
+                       } else if {
+                               g-dup-func gpointer
+                           GParamPointer
+                           $43 = {g_type_instance = {g_class = 0x67ad30}, name = 0x7ffff7b7d685 
"g-dup-func", flags = 234, value_type = 68, owner_type = 14758512, _nick = 0x7ffff7b7d67c "dup func", _blurb =
+                               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));
+                                       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?
+                                       // TODO: Make copy_node public to allow others to use it
+                                       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 
());
+                       }
+
+                       return value_node;
+               }
+
+               /**
+                * Serializes a { link GLib.Object} into a { link GXml.Document}.
+                *
+                * This takes a { link GLib.Object} and serializes it
+                * into a { link GXml.Document} which can be saved to
+                * disk or transferred over a network.  It handles
+                * serialization of primitive properties and some more
+                * complex ones like enums, other { link GLib.Object}s
+                * recursively, and some collections.
+                *
+                * The serialization process can be customised for an object
+                * by having the object implement the { link GXml.Serializable}
+                * interface, which allows direct control over the
+                * conversation of individual properties into { link GXml.Node}s
+                * and the object's list of properties as used by
+                * { link GXml.Serialization}.
+                *
+                * A { link GXml.SerializationError} may be thrown if there is
+                * a problem serializing a property (e.g. the type is unknown,
+                * unsupported, or the property isn't known to the object).
+                *
+                * @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
+               {
+                       Document doc;
+                       Element root;
+                       ParamSpec[] prop_specs;
+                       Element prop;
+                       GXml.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");
+                               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);
+                       }
+
+                       /* Debug output */
+                       bool debug = false;
+                       if (debug) {
+                               Serialization.print_debug (doc, object);
+                       }
+
+                       return doc;
+               }
+
+               /*
+                * This handles deserializing properties individually.
+                * Because { link GLib.Value} doesn't handle transforming
+                * 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
+               {
+                       Type type;
+                       type = spec.value_type;
+                       // Get value and save this all as a parameter
+                       val = Value (type);
+                       if (GLib.Value.type_transformable (type, typeof (string))) {
+                                       Serializable.string_to_gvalue (prop_elem.content, ref val);
+                       } 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);
+                       }
+               }
+
+               /**
+                * 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!!!!*/
+               private static HashTable<string,Object> deserialize_cache = null;
+               private static HashTable<string,GXml.Node> serialize_cache = null;
+               // public so that tests can call it
+               public static void clear_cache () { // TODO: rename to clear_caches, just changed back 
temporarily to avoid API break for 0.3.2
+                       if (Serialization.deserialize_cache != null)
+                               Serialization.deserialize_cache.remove_all ();
+                       if (Serialization.serialize_cache != null)
+                               Serialization.serialize_cache.remove_all ();
+               }
+
+               private static void init_caches () {
+                       if (Serialization.deserialize_cache == null) {
+                               Serialization.deserialize_cache = new HashTable<string,Object> (str_hash, 
str_equal);
+                       }
+                       if (Serialization.serialize_cache == null) {
+                               Serialization.serialize_cache = new HashTable<string,GXml.Node> (str_hash, 
str_equal);
+                       }
+               }
+
+               /**
+                * Deserialize a { link GXml.Document} back into a { link GLib.Object}.
+                *
+                * This deserializes a { link GXml.Document} back into a
+                * { link GLib.Object}.  The { link GXml.Document}
+                * must represent a { link GLib.Object} as serialized
+                * by { link GXml.Serialization}.  The types of the
+                * objects that are being deserialized must be known
+                * 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
+                * @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
+               {
+                       Element obj_elem;
+                       string otype;
+                       string oid;
+                       Type type;
+                       Object obj;
+                       unowned ObjectClass obj_class;
+                       ParamSpec[] specs;
+
+                       obj_elem = (Element)obj_node;
+
+                       // FIXME: Remove cache.
+                       // If the object has been deserialised before, get it from cache
+                       oid = obj_elem.get_attribute ("oid");
+                       Serialization.init_caches ();
+                       if (oid != "" && Serialization.deserialize_cache.contains (oid)) {
+                               return Serialization.deserialize_cache.get (oid);
+                       }
+
+                       // Get the object's type
+                       // TODO: wish there was a g_object_class_from_name () method
+                       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;
+                       }
+
+                       // Get the list of properties as ParamSpecs
+                       obj = Object.newv (type, new Parameter[] {}); // TODO: causes problems with Enums 
when 0 isn't a valid enum value (e.g. starts from 2 or something)
+                       obj_class = obj.get_class ();
+
+                       // 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 ();
+
+                       foreach (GXml.Node child_node in obj_elem.child_nodes) {
+                               if (child_node.node_name == "Property") {
+                                       Element prop_elem;
+                                       string pname;
+                                       Value val;
+
+                                       prop_elem = (Element)child_node;
+                                       pname = prop_elem.get_attribute ("pname");
+                                       // Check name and type for property
+                                       ParamSpec? spec = null;
+                                       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;
+                                       }
+                                       Serialization.deserialize_property (spec, prop_elem, out val);
+                                       obj.set_property (pname, val);
+                               }
+                       }
+                       return obj;
+               }
+       }
+}
diff --git a/test/SerializableTest.vala b/test/SerializableTest.vala
index 7b914d7..e5a9b0a 100644
--- a/test/SerializableTest.vala
+++ b/test/SerializableTest.vala
@@ -51,7 +51,7 @@ using Gee;
    Test overriding {set,get}_property
 */
 
-public class SerializableTomato : GXml.SerializableJson {
+public class SerializableTomato : Xom.SerializableJson {
        public int weight;
        private int age { get; set; }
        public int height { get; set; }
@@ -77,7 +77,7 @@ public class SerializableTomato : GXml.SerializableJson {
        }
 }
 
-public class SerializableCapsicum : GXml.SerializableJson {
+public class SerializableCapsicum : Xom.SerializableJson {
        public int weight;
        private int age { get; set; }
        public int height { get; set; }
@@ -97,8 +97,8 @@ public class SerializableCapsicum : GXml.SerializableJson {
                this.age = age;
                this.height = height;
                this.ratings = ratings;
-               ((GXml.Serializable)this).serialize_unknown_property_type.connect 
(serialize_unknown_property_type);
-               ((GXml.Serializable)this).deserialize_unknown_property_type.connect 
(deserialize_unknown_property_type);
+               ((Xom.Serializable)this).serialize_unknown_property_type.connect 
(serialize_unknown_property_type);
+               ((Xom.Serializable)this).deserialize_unknown_property_type.connect 
(deserialize_unknown_property_type);
        }
 
        /* TODO: do we really need GLib.Value? or should we modify the object directly?
@@ -140,7 +140,7 @@ public class SerializableCapsicum : GXml.SerializableJson {
 }
 
 
-public class SerializableBanana : GXml.SerializableJson {
+public class SerializableBanana : Xom.SerializableJson {
        private int private_field;
        public int public_field;
        private int private_property { get; set; }
diff --git a/test/SerializationTest.vala b/test/SerializationTest.vala
index bd26691..6672780 100644
--- a/test/SerializationTest.vala
+++ b/test/SerializationTest.vala
@@ -1,5 +1,6 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
 using GXml;
+using Xom;
 using Gee;
 
 /**
@@ -323,7 +324,7 @@ class SerializationTest : GXmlTest {
                                        Test.message ("Regular expression [%s] for test failed: %s",
                                                      expectation, e.message);
                                        assert_not_reached ();
-                               } catch (GXml.SerializationError e) {
+                               } catch (Xom.SerializationError e) {
                                        Test.message ("%s", e.message);
                                        assert_not_reached ();
                                } catch (GLib.Error e) {
@@ -373,7 +374,7 @@ class SerializationTest : GXmlTest {
                                        assert_not_reached ();
                                } catch (GLib.Error e) {
                                        //stdout.printf (@"Cought Error: $(e.message)");
-                                       if (e is GXml.SerializationError.UNKNOWN_PROPERTY) {
+                                       if (e is Xom.SerializationError.UNKNOWN_PROPERTY) {
                                                // pass
                                        } else {
                                                GLib.message (@"Error is not UNKNOWN_PROPERTY: $(e.message)");
@@ -389,7 +390,7 @@ class SerializationTest : GXmlTest {
                                        Serialization.deserialize_object (0, doc);
                                        assert_not_reached ();
                                } catch (GLib.Error e) {
-                                       if (e is SerializationError.UNKNOWN_TYPE) {
+                                       if (e is Xom.SerializationError.UNKNOWN_TYPE) {
                                        // pass
                                        }
                                        else {
@@ -410,7 +411,7 @@ class SerializationTest : GXmlTest {
                                        fruit = (Fruit)Serialization.deserialize_object (typeof (Fruit), doc);
                                        assert_not_reached ();
                                } catch (GLib.Error e) {
-                                       if (e is SerializationError.UNKNOWN_PROPERTY)
+                                       if (e is Xom.SerializationError.UNKNOWN_PROPERTY)
                                        { // pass
                                        }
                                        else {


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