Skip to content
Snippets Groups Projects
Commit 1d366454 authored by Richard Schwarting's avatar Richard Schwarting
Browse files

* add documentation for Serialization and Serializable

parent 56b80b3a
No related branches found
No related tags found
No related merge requests found
......@@ -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);
}
......
/*
* 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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment