[gxml/serialization: 171/172] Implemented proof of concept of SerializabelJson and SerializableObjectModel * Serializable methods
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gxml/serialization: 171/172] Implemented proof of concept of SerializabelJson and SerializableObjectModel * Serializable methods
- Date: Wed, 9 Oct 2013 20:57:42 +0000 (UTC)
commit 2a2b8fcad86a7f5f73a2dc03492aa42af423a29e
Author: Daniel Espinosa <esodan gmail com>
Date: Wed Oct 9 15:31:07 2013 -0500
Implemented proof of concept of SerializabelJson and SerializableObjectModel
* Serializable methods has been implemented by SerializableJson
* SerializableJson implements Serializable interface
* SerializableObjectModel implements Serializable interface
* Serializable interface defined to use both or any future serialization method
* Serializable spects to add nodes to a given Node, if is Document a root
if an Element childs Nodes.
* Serializable can be used to serialize objects implementing it
gxml/Makefile.am | 2 +
gxml/Serializable.vala | 329 ++++++++++++++++++++++++++++++++-----
gxml/SerializableJson.vala | 213 ++++++++++++++++++++++++
gxml/SerializableObjectModel.vala | 200 ++++++++++++++++++++++
4 files changed, 701 insertions(+), 43 deletions(-)
---
diff --git a/gxml/Makefile.am b/gxml/Makefile.am
index 8f6d972..bb40117 100644
--- a/gxml/Makefile.am
+++ b/gxml/Makefile.am
@@ -60,6 +60,8 @@ libgxml_la_SOURCES = \
ProcessingInstruction.vala \
Text.vala \
Serializable.vala \
+ SerializableObjectModel.vala \
+ SerializableJson.vala \
Serialization.vala \
$(NULL)
diff --git a/gxml/Serializable.vala b/gxml/Serializable.vala
index 53ac7fc..b21a2f9 100644
--- a/gxml/Serializable.vala
+++ b/gxml/Serializable.vala
@@ -2,6 +2,7 @@
/* Serializable.vala
*
* Copyright (C) 2011-2013 Richard Schwarting <aquarichy gmail com>
+ + Copyright (C) 2013 Daniel Espinosa <esodan gmail com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,6 +19,7 @@
*
* Authors:
* Richard Schwarting <aquarichy gmail com>
+ * Daniel Espinosa <esodan gmail com>
*/
@@ -70,39 +72,43 @@ namespace GXml {
*/
public interface Serializable : GLib.Object {
/**
- * Handles deserializing individual properties.
+ * Defines the way to set Node name.
*
- * Interface method to handle deserialization of an
- * individual property. The implementing class
- * receives a description of the property and the
- * { link GXml.Node} that contains the content. The
- * implementing { link GXml.Serializable} object can extract
- * the data from the { link GXml.Node} and store it in its
- * property itself. Note that the { link GXml.Node} may be
- * as simple as a { link GXml.Text} that stores the data as a
- * string.
+ * By default is set to object's type's name lowercase.
*
- * 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.
+ * This property must be ignored on serialisation.
+ */
+ public abstract string serializable_node_name { get; protected set; }
+
+ public abstract bool serializable_property_use_nick { get; set; }
+ /**
+ * Store all properties to be ignored on serialization.
*
- * @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.Node} encapsulating data to deserialize
- * @return `true` if the property was handled, `false` if { link GXml.Serialization} should
handle it.
+ * Implementors: By default { link list_serializable_properties} initialize
+ * this property to store all public properties, except this one.
*/
- /*
- * @todo: consider not giving property_name, but
- * letting them get name from spec
- * @todo: consider returning { link GLib.Value} as out param
+ public abstract HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get;
protected set; }
+ /**
+ * On deserialization stores any { link Node} not used on this
+ * object, but exists in current XML file.
+ *
+ * This property must be ignored on serialisation.
*/
- public virtual bool deserialize_property (string property_name, /* out GLib.Value value,*/
GLib.ParamSpec spec, GXml.Node property_node) {
- return false; // default deserialize_property gets used
- }
+ public abstract HashTable<string,GXml.Node> unknown_serializable_property { get; protected
set; }
+
+ /**
+ * Used by to add content in an { link GXml.Element}.
+ *
+ * This property must be ignored on serialisation.
+ */
+ public abstract string? serialized_xml_node_value { get; protected set; default = null; }
+
+ /**
+ * Serialize this object.
+ *
+ * @doc an { link GXml.Document} object to serialise to
+ */
+ public abstract Node? serialize (Node node);
/**
* Handles serializing individual properties.
@@ -126,15 +132,70 @@ namespace GXml {
* @param doc the { link GXml.Document} the returned { link GXml.Node} should belong to
* @return a new { link GXml.Node}, or `null`
*/
- /*
- * @todo: consider not giving property_name, let them get name from spec?
+ public abstract GXml.Node? serialize_property (Element element,
+ GLib.ParamSpec prop);
+
+ /**
+ * Deserialize this object.
+ *
+ * @node { link GXml.Node} used to deserialize from.
*/
- public virtual GXml.Node? serialize_property (string property_name, /*GLib.Value value, */
GLib.ParamSpec spec, GXml.Document doc) {
- return null; // default serialize_property gets used
- }
+ public abstract Node? deserialize (Node node)
+ throws SerializableError;
+ /**
+ * 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.Node} that contains the content. The
+ * implementing { link GXml.Serializable} object can extract
+ * the data from the { link GXml.Node} and store it in its
+ * property itself. Note that the { link GXml.Node} may be
+ * as simple as a { link GXml.Text} that stores the data as a
+ * string.
+ *
+ * @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.Node} encapsulating data to deserialize
+ * @return `true` if the property was handled, `false` if { link GXml.Serialization} should
handle it.
+ */
+ public abstract bool deserialize_property (GXml.Node property_node)
+ throws SerializableError;
+
+ /**
+ * Signal to serialize unknown properties.
+ *
+ * @element a { link GXml.Node} to add attribute or child nodes to
+ * @prop a { link GLib.ParamSpec} describing attribute to serialize
+ * @node set to the { link GXml.Node} representing this attribute
+ */
+ public signal void serialize_unknown_property (Node element, ParamSpec prop, out Node node);
- /* Correspond to: g_object_class_{find_property,list_properties} */
+ /**
+ * Signal to serialize unknown properties.
+ *
+ * @element a { link GXml.Node} to add attribute or child nodes to
+ * @prop a { link GLib.ParamSpec} describing attribute to serialize
+ * @node set to the { link GXml.Node} representing this attribute
+ */
+ public signal void serialize_unknown_property_type (Node element, ParamSpec prop, out Node
node);
+
+ /**
+ * Signal to deserialize unknown properties.
+ *
+ * @node a { link GXml.Node} to get attribute from
+ * @prop a { link GLib.ParamSpec} describing attribute to deserialize
+ */
+ public signal void deserialize_unknown_property (Node node, ParamSpec prop);
+ /**
+ * Signal to deserialize unknown properties' type.
+ *
+ * @node a { link GXml.Node} to get attribute from
+ * @prop a { link GLib.ParamSpec} describing attribute to deserialize
+ */
+ public signal void deserialize_unknown_property_type (Node node, ParamSpec prop);
/*
* Handles finding the { link GLib.ParamSpec} for a given property.
*
@@ -163,8 +224,39 @@ namespace GXml {
* { 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
+ public virtual GLib.ParamSpec? find_property_spec (string property_name) {
+ init_properties ();
+ string pn = property_name.down ();
+ if (ignored_serializable_properties.contains (pn)) {
+ return null;
+ }
+ return get_class ().find_property (pn);
+ }
+
+ /**
+ * Used internally to initialize { link ignored_serializable_properties} property
+ * and default not to be serialized properties. Unless you override any function
+ * is not required to be called at class implementor's construction time.
+ *
+ */
+ public virtual void init_properties ()
+ {
+ if (ignored_serializable_properties == null) {
+ ignored_serializable_properties = new HashTable<string,ParamSpec> (str_hash,
str_equal);
+ ignored_serializable_properties.set ("ignored-serializable-properties",
+ get_class
().find_property("ignored-serializable-properties"));
+ ignored_serializable_properties.set ("unknown-serializable-property",
+ get_class
().find_property("unknown-serializable-property"));
+ ignored_serializable_properties.set ("serialized-xml-node-value",
+ get_class
().find_property("serialized-xml-node-value"));
+ ignored_serializable_properties.set ("serializable-property-use-nick",
+ get_class
().find_property("serializable-property-use-nick"));
+ ignored_serializable_properties.set ("serializable-node-name",
+ get_class
().find_property("serializable-node-name"));
+ }
+ if (unknown_serializable_property == null) {
+ unknown_serializable_property = new HashTable<string,GXml.Node> (str_hash,
str_equal);
+ }
}
/*
@@ -195,8 +287,16 @@ namespace GXml {
* { 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 ();
+ public virtual GLib.ParamSpec[] list_serializable_properties ()
+ {
+ init_properties ();
+ ParamSpec[] props = {};
+ foreach (ParamSpec spec in this.get_class ().list_properties ()) {
+ if (!ignored_serializable_properties.contains (spec.name)) {
+ props += spec;
+ }
+ }
+ return props;
}
/*
@@ -228,14 +328,26 @@ namespace GXml {
* @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);
+ public virtual string get_property_value (GLib.ParamSpec spec)
+ {
+ Value val = Value (spec.value_type);
+ if (!ignored_serializable_properties.contains (spec.name))
+ {
+ Value ret = "";
+ ((GLib.Object)this).get_property (spec.name, ref val);
+ if (Value.type_transformable (val.type (), typeof (string)))
+ {
+ val.transform (ref ret);
+ return ret.dup_string ();
+ }
+ }
+ return "";
}
/*
* Set a property's value.
*
* @param spec Specifies the property whose value will be set
- * @param value The value to set the property to.
+ * @param val The value to set the property to.
*
* { link GXml.Serialization} uses { link GLib.Object.set_property} (as
* well as { link GLib.ObjectClass.find_property},
@@ -253,8 +365,139 @@ namespace GXml {
* 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);
+ public virtual void set_property_value (GLib.ParamSpec spec, GLib.Value val)
+ {
+ if (!ignored_serializable_properties.contains (spec.name)) {
+ ((GLib.Object)this).set_property (spec.name, val);
+ }
+ }
+ /* TODO:
+ * - 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 #GXmlSerializableError 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 SerializableError
+ {
+ Type t = dest.type ();
+ GLib.Value dest2 = Value (t);
+ bool ret = false;
+
+ if (t == typeof (int64)) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_int64 (val);
+ }
+ } else if (t == typeof (int)) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_int ((int)val);
+ }
+ } else if (t == typeof (long)) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_long ((long)val);
+ }
+ } else if (t == typeof (uint)) {
+ uint64 val;
+ if (ret = uint64.try_parse (str, out val)) {
+ dest2.set_uint ((uint)val);
+ }
+ } else if (t == typeof (ulong)) {
+ uint64 val;
+ if (ret = uint64.try_parse (str, out val)) {
+ dest2.set_ulong ((ulong)val);
+ }
+ } else if ((int)t == 20) { // gboolean
+ bool val = (str == "TRUE");
+ dest2.set_boolean (val); // TODO: huh, investigate why the type is gboolean
and not bool coming out but is going in
+ ret = true;
+ } else if (t == typeof (bool)) {
+ bool val;
+ if (ret = bool.try_parse (str, out val)) {
+ dest2.set_boolean (val);
+ }
+ } else if (t == typeof (float)) {
+ double val;
+ if (ret = double.try_parse (str, out val)) {
+ dest2.set_float ((float)val);
+ }
+ } else if (t == typeof (double)) {
+ double val;
+ if (ret = double.try_parse (str, out val)) {
+ dest2.set_double (val);
+ }
+ } else if (t == typeof (string)) {
+ dest2.set_string (str);
+ ret = true;
+ } else if (t == typeof (char)) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_char ((char)val);
+ }
+ } else if (t == typeof (uchar)) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_uchar ((uchar)val);
+ }
+ } else if (t == Type.BOXED) {
+ } else if (t.is_enum ()) {
+ int64 val;
+ if (ret = int64.try_parse (str, out val)) {
+ dest2.set_enum ((int)val);
+ }
+ } else if (t.is_flags ()) {
+ } else if (t.is_object ()) {
+ } else {
+ }
+
+ if (ret == true) {
+ dest = dest2;
+ return true;
+ } else {
+ throw new SerializableError.UNSUPPORTED_TYPE ("%s/%s", t.name (), t.to_string
());
+ }
}
+
+ public static string gvalue_to_string (GLib.Value val)
+ throws SerializableError
+ {
+ Value ret = "";
+ if (Value.type_transformable (val.type (), typeof (string)))
+ {
+ val.transform (ref ret);
+ return ret.dup_string ();
+ }
+ else
+ {
+ throw new SerializableError.UNSUPPORTED_TYPE ("Can't transform '%s' to
string", val.type ().name ());
+ }
+ }
+ }
+
+ /**
+ * Errors from { link Serialization}.
+ */
+ public errordomain SerializableError {
+ /**
+ * An object with a known { link GLib.Type} that we do not support was encountered.
+ */
+ UNSUPPORTED_TYPE
}
}
diff --git a/gxml/SerializableJson.vala b/gxml/SerializableJson.vala
new file mode 100644
index 0000000..a207650
--- /dev/null
+++ b/gxml/SerializableJson.vala
@@ -0,0 +1,213 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Serialization.vala
+ *
+ * Copyright (C) 2012-2013 Richard Schwarting <aquarichy gmail com>
+ * Copyright (C) 2013 Daniel Espinosa <esodan 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>
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+/**
+ * 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 GXml.SerializableJason : GLib.Object, Serializable
+{
+ /* Serializable Interface properties */
+ public string serializable_node_name { get; protected set; }
+ public bool serializable_property_use_nick { get; set; }
+ public HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
+ public HashTable<string,GXml.Node> unknown_serializable_property { get; protected set; }
+
+ public string? serialized_xml_node_value { get; protected set; default = null; }
+
+ /**
+ * If @node is a Document serialize just add an <Object> element.
+ *
+ * If @node is an Element serialize add to it an <Object> element.
+ *
+ * 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)
+ {
+ Document doc;
+ Element root;
+ ParamSpec[] prop_specs;
+ Element prop;
+ Node value_prop = null;
+ string oid = "%p".printf(this);
+
+ if (node is Document)
+ doc = (Document) node;
+ else
+ doc = node.owner_document;
+
+ root = doc.create_element ("Object");
+ doc.append_child (root);
+ root.set_attribute ("otype", object.get_type ().name ());
+ root.set_attribute ("oid", oid);
+
+ prop_specs = serializable.list_properties ();
+
+ 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 = serialize_property (prop, prop_spe);
+ prop.append_child (value_prop);
+ root.append_child (prop);
+ }
+ return root;
+ }
+
+ public GXml.Node? serialize_property (Element element,
+ GLib.ParamSpec prop)
+ {
+ Type type;
+ Value value;
+ Node value_node = null;
+
+ type = prop.value_type;
+
+ if (type.is_a (typeof (Serializable)))
+ return (Serializable).serialize ();
+
+ var doc = element.owner_document;
+
+ if (type.is_enum ())
+ {
+ value = Value (typeof (int));
+ this.get_property (prop_spec.name, ref value);
+ value_node = doc.create_text_node ("%d".printf (value.get_int ()));
+ }
+ else if (Value.type_transformable (type, typeof (string)))
+ { // e.g. int, double, string, bool
+ value = Value (typeof (string));
+ this.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 (GLib.Object))
+ && ! type.is_a (typeof (Gee.Collection)))
+ {
+ GLib.Object child_object;
+
+ // TODO: this is going to get complicated
+ value = Value (typeof (GLib.Object));
+ this.get_property (prop.name, ref value);
+ child_object = value.get_object ();
+ Document value_doc = Serialization.serialize_object (child_object);
+
+ 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.name);
+ } else {
+ throw new SerializationError.UNSUPPORTED_TYPE ("Can't currently serialize type '%s'
for property '%s' of object '%s'", type.name (), prop.name, object.get_type ().name ());
+ }
+
+ return value_node;
+ }
+
+ public Node? deserialize (Node node) throws SerializableError
+ {
+ bool ret = true;
+ Element obj_elem;
+ string otype;
+ string oid;
+ Type type;
+ ParamSpec[] specs;
+
+ if (node is Document) {
+ obj_elem = node.owner_document.document_element;
+ }
+ else {
+ obj_elem = (Element) node;
+ }
+
+ specs = this.list_serializable_properties ();
+
+ foreach (Node child_node in obj_elem.child_nodes) {
+ deserialize_property (child_node);
+ }
+ return obj_elem;
+ }
+
+ public bool deserialize_property (GXml.Node property_node) throws SerializableError
+ {
+ if (properly_node.node_name == "Property")
+ {
+ Element prop_elem;
+ string pname;
+ Value val;
+ //string ptype;
+
+ prop_elem = (Element)child_node;
+ pname = prop_elem.get_attribute ("pname");
+ //ptype = prop_elem.get_attribute ("ptype"); // optional
+
+ // Check name and type for property
+ spec = this.find_property_spec (pname);
+
+ if (spec == null) {
+ GLib.message ("Deserializing object of type '%s' claimed unknown property
named '%s'\nXML [%s]", otype, pname, obj_elem.to_string ());
+ unknown_serializable_property.set (property_node.node_name, property_node);
+ continue;
+ }
+ else {
+ if (spec.value_type ().is_a (typeof(Serializable)))
+ {
+ Value vobj;
+ this.get_property (pname, out vobj);
+ ((Serializable) vobj).deserialize (child_node);
+ }
+ else {
+ val = Value (type);
+ if (GLib.Value.type_transformable (type, typeof (string))) {
+ Serializable.string_to_gvalue (prop_elem.content, ref val);
+ this.set_property_value (pname, 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);
+ }
+ else {
+ deserialize_unknown_property_type.set (prop_elem, spec);
+ ret = false;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/gxml/SerializableObjectModel.vala b/gxml/SerializableObjectModel.vala
new file mode 100644
index 0000000..b554154
--- /dev/null
+++ b/gxml/SerializableObjectModel.vala
@@ -0,0 +1,200 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* ObjectModel.vala
+ *
+ * Copyright (C) 2013 Daniel Espinosa <esodan 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:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+public abstract class GXml.SerializableObjectModel : Object, Serializable
+{
+ /* Serializable interface properties */
+ public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
+ public bool serializable_property_use_nick { get; set; }
+ public string? serialized_xml_node_value { get; protected set; default=null; }
+ public GLib.HashTable<string,GXml.Node> unknown_serializable_property { get; protected set; }
+ public string serializable_node_name { get; protected set; }
+
+ public SerializableObjectModel ()
+ {
+ serializable_property_use_nick = true;
+ serialized_xml_node_value = null;
+ serializable_node_name = get_type().name().down();
+ }
+
+ public Node? serialize (Node node)
+ {
+ Document doc;
+ if (node is Document)
+ doc = (Document) node;
+ else
+ doc = node.owner_document;
+ GLib.message ("Serialing on ..." + node.node_name);
+ var element = doc.create_element (serializable_node_name);
+ node.append_child (element);
+ if (serialized_xml_node_value != null)
+ element.content = serialized_xml_node_value;
+ GLib.message ("Node Value is: ?" + element.content);
+ foreach (ParamSpec spec in list_serializable_properties ()) {
+ GLib.message ("Property to Serialize: " + spec.name);
+ serialize_property (element, spec);
+ }
+ GLib.message ("Added a new top node: " + element.node_name);
+ return element;
+ }
+
+ public GXml.Node? serialize_property (Element element,
+ GLib.ParamSpec prop)
+ {
+ 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);
+ }
+ Node node = null;
+ 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 (Node) attr;
+ }
+ this.serialize_unknown_property (element, prop, out node);
+ return node;
+ }
+
+ public virtual Node? deserialize (Node node)
+ throws SerializableError
+ {
+ Document doc;
+ if (node is Document) {
+ doc = (Document) node;
+ return_val_if_fail (doc.document_element != null, null);
+ }
+ else
+ doc = node.owner_document;
+ Element element;
+ if (node is Element)
+ element = (Element) node;
+ else
+ element = (Element) doc.document_element;
+ return_val_if_fail (element.node_name.down () == serializable_node_name, null);
+ foreach (Attr attr in element.attributes.get_values ())
+ {
+ GLib.message (@"Deseralizing Attribute: $(attr.name)");
+ deserialize_property (attr);
+ }
+ if (element.has_child_nodes ())
+ {
+ GLib.message ("Have child Elements ...");
+ foreach (Node n in element.child_nodes)
+ {
+ GLib.message (@"Deseralizing Element: $(n.node_name)");
+ deserialize_property (n);
+ }
+ }
+ if (element.content != null)
+ serialized_xml_node_value = element.content;
+ return null;
+ }
+
+ public virtual bool deserialize_property (GXml.Node property_node)
+ throws SerializableError
+ {
+ bool ret = false;
+ var prop = find_property_spec (property_node.node_name);
+ if (prop == null) {
+ GLib.message ("Found Unknown property: " + property_node.node_name);
+ // FIXME: Event emit
+ unknown_serializable_property.set (property_node.node_name, property_node);
+ return true;
+ }
+ if (prop.value_type.is_a (typeof (Serializable)))
+ {
+ GLib.message (@"$(prop.name): Is Serializable...");
+ Value vobj = Value (typeof(Object));
+ get_property (prop.name, ref vobj);
+ if (vobj.get_object () == null) {
+ 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;
+ }
+ else {
+ Value val = Value (prop.value_type);
+ if (Value.type_transformable (typeof (Node), prop.value_type))
+ {
+ Value tmp = Value (typeof (Node));
+ 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);
+ if (Value.type_transformable (typeof (string), prop.value_type))
+ ret = ptmp.transform (ref val);
+ else
+ ret = string_to_gvalue (property_node.node_value, ref val);
+ set_property (prop.name, val);
+ return ret;
+ }
+ }
+ // Attribute can't be deseralized with standard methods. Up to the implementor.
+ this.deserialize_unknown_property (property_node, prop);
+ return true;
+ }
+ public abstract string to_string ();
+
+ public static bool equals (SerializableObjectModel a, SerializableObjectModel b)
+ {
+ if (b.get_type () == a.get_type ()) {
+ var alp = ((Serializable)a).list_serializable_properties ();
+ bool ret = true;
+ foreach (ParamSpec p in alp) {
+ var bp = ((Serializable)b).find_property_spec (p.name);
+ if (bp != null) {
+ var apval = ((Serializable)a).get_property_value (p);
+ var bpval = ((Serializable)b).get_property_value (bp);
+ if ( apval != bpval)
+ ret = false;
+ }
+ }
+ return ret;
+ }
+ return false;
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]