[gxml] * add documentation for Serialization and Serializable
- From: Richard Hans Schwarting <rschwart src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gxml] * add documentation for Serialization and Serializable
- Date: Mon, 13 Aug 2012 19:52:26 +0000 (UTC)
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]