[gxml] * add documentation for Serialization and Serializable



commit 1d366454accdaaebf1d170805c8babf5d875a104
Author: Richard Schwarting <aquarichy gmail com>
Date:   Mon Aug 13 15:49:55 2012 -0400

    * add documentation for Serialization and Serializable

 gxml/Serializable.vala  |  194 ++++++++++++++++++++++++++++++++++++++++++++--
 gxml/Serialization.vala |  134 +++++++++++++++++++++++++++++----
 2 files changed, 304 insertions(+), 24 deletions(-)
---
diff --git a/gxml/Serializable.vala b/gxml/Serializable.vala
index ee700d5..caab9e8 100644
--- a/gxml/Serializable.vala
+++ b/gxml/Serializable.vala
@@ -30,34 +30,210 @@ using GXml;
 
 [CCode (gir_namespace = "GXml", gir_version = "0.2")]
 namespace GXml {
+	/**
+	 * Provides interface methods that a class can implement to
+	 * directly handle serialisation of various properties or
+	 * treat other data as properties.
+	 *
+	 * 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.
+	 *
+	 * For an example, look in tests/XmlSerializableTest
+	 */
 	public interface Serializable : GLib.Object {
-		/** Return true if your implementation will have handled the given property,
-		    and false elsewise (in which case, XmlSerializable will try to deserialize
-		    it).  */
-		/** OBSOLETENOTE: Return the deserialized value in GLib.Value (even if it's a GLib.Boxed type) because Serializer is going to set the property after calling this, and if you just set it yourself within, it will be overwritten */
+		/**
+		 * 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.DomNode} that contains the content.  The
+		 * implementing { link GXml.Serializable} object can extract
+		 * the data from the { link GXml.DomNode} and store it in its
+		 * property itself. Note that the { link GXml.DomNode} 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.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 (string property_name, /* out GLib.Value value,*/ GLib.ParamSpec spec, GXml.DomNode property_node) {
 			return false; // default deserialize_property gets used
 		}
-		// TODO: just added ? to these, do we really want to allow nulls for them?
-		// TODO: value and property_name are kind of redundant: eliminate?  property_name from spec.property_name and value from the object itself :)
-		/** Serialized properties should have the XML structure <Property pname="PropertyName">...</Property> */
-		// TODO: perhaps we should provide that base structure
+
+		/**
+		 * 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`
+		 */
+		/*
+		 * @todo: consider not giving property_name, let them get name from spec?
+		 */
 		public virtual GXml.DomNode? serialize_property (string property_name, /*GLib.Value value, */ GLib.ParamSpec spec, GXml.Document doc) {
 			return null; // default serialize_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 ();
 		}
 
-		/* Correspond to: g_object_{set,get}_property */
+		/*
+		 * 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/Serialization.vala
index ea7e163..f8ddf11 100644
--- a/gxml/Serialization.vala
+++ b/gxml/Serialization.vala
@@ -1,25 +1,59 @@
+/*
+ * Copyright (C) 2012 Richard Schwarting
+ *
+ * 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;
 
 [CCode (gir_namespace = "GXml", gir_version = "0.2")]
 namespace GXml {
+	/**
+	 * Errors from { link Serialization}.
+	 */
 	public errordomain SerializationError {
+		/**
+		 * An object without a known { link GLib.Type} was encountered.
+		 */
 		UNKNOWN_TYPE,
+		/**
+		 * A property was described in XML that is not known to the object's type.
+		 */
 		UNKNOWN_PROPERTY,
+		/**
+		 * An object with a known { link GLib.Type} that we do not support was encountered.
+		 */
 		UNSUPPORTED_TYPE
 	}
 
 	/**
-	 * SECTION:gxml-serialization
-	 * @short_description: Provides functions for serializing GObjects.
-	 * @x-title:gxml-serialization
-	 * @section_id:
-	 * @see_also: #GXml, #GXmlDocument, #GObject
-	 * @stability: Unstable
-	 * @include: gxml/serialization.h
-	 * @image: library.png
+	 * Serializes and deserializes { link GLib.Object}s to and from
+	 * { link GXml.DomNode}.
 	 *
-	 * GXmlSerialization provides functions to serialize and
-	 * deserialize GObjects into and from GXmlDomNodes
+	 * 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) {
@@ -43,8 +77,12 @@ namespace GXml {
 			}
 		}
 
-		// public delegate void GetProperty (GLib.ParamSpec spec, ref GLib.Value value);
-
+		/*
+		 * 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.DomNode serialize_property (GLib.Object object, ParamSpec prop_spec, GXml.Document doc) throws SerializationError, DomError {
 			Type type;
 			Value value;
@@ -109,9 +147,29 @@ namespace GXml {
 			return value_node;
 		}
 
-		/* TODO: so it seems we can get property information from GObjectClass
-		   but that's about it.  Need to definitely use introspection for anything
-		   tastier */
+		/**
+		 * Serializes a { link GLib.Object} into a { link GXml.DomNode}.
+		 *
+		 * This takes a { link GLib.Object} and serializes it into a
+		 * { link GXml.DomNode} 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.DomNode}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.DomNode} representing the serialized `object`
+		 */
 		public static GXml.DomNode serialize_object (GLib.Object object) throws SerializationError {
 			Document doc;
 			Element root;
@@ -179,6 +237,12 @@ namespace GXml {
 			return doc.document_element; // user can get Document through .owner_document
 		}
 
+		/*
+		 * 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 SerializationError {
 			Type type;
 
@@ -227,6 +291,29 @@ namespace GXml {
 			}
 		}
 
+		/*
+		 * 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. */
+		private static HashTable<string,Object> cache = null;
+
+		/**
+		 * Deserialize a { link GXml.DomNode} back into a { link GLib.Object}.
+		 *
+		 * This deserializes a { link GXml.DomNode} back into a { link GLib.Object}.  The
+		 * { link GXml.DomNode} must represented 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.
+		 *
+		 * @param node { link GXml.DomNode} representing a { link GLib.Object}
+		 * @return the deserialized { link GLib.Object}
+		 */
 		public static GLib.Object deserialize_object (DomNode node) throws SerializationError {
 			Element obj_elem;
 
@@ -314,6 +401,23 @@ namespace GXml {
 		 * - 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);



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