[gxml/serialization_isolation] Xom,Jgs merging: re-namespace things
- From: Richard Hans Schwarting <rschwart src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gxml/serialization_isolation] Xom,Jgs merging: re-namespace things
- Date: Wed, 2 Apr 2014 15:19:00 +0000 (UTC)
commit 1b1db425a05857a94d3979b73bf37c2a47478eef
Author: Richard Schwarting <aquarichy gmail com>
Date: Wed Apr 2 11:16:06 2014 -0400
Xom,Jgs merging: re-namespace things
gxml/Makefile.am | 24 +-
gxml/Serializable.vala | 567 --------------------
gxml/SerializableObjectModel.vala | 381 -------------
gxml/jgs/JgsSerializable.vala | 363 +++++++++++++
.../JgsSerialization.vala} | 434 ++++++++++-----
gxml/{ => xom}/Enumeration.vala | 2 +-
gxml/{ => xom}/SerializableContainer.vala | 4 +-
gxml/{ => xom}/SerializableGeeArrayList.vala | 2 +-
gxml/{ => xom}/SerializableGeeDualKeyMap.vala | 2 +-
gxml/{ => xom}/SerializableGeeHashMap.vala | 2 +-
gxml/{ => xom}/SerializableGeeTreeMap.vala | 2 +-
gxml/{ => xom}/SerializableJson.vala | 2 +-
gxml/{ => xom}/SerializableMapDualKey.vala | 2 +-
gxml/{ => xom}/SerializableMapKey.vala | 2 +-
gxml/xom/SerializableObjectModel.vala | 383 +++++++++++++
15 files changed, 1068 insertions(+), 1104 deletions(-)
---
diff --git a/gxml/Makefile.am b/gxml/Makefile.am
index 8dd9cbb..1c174a5 100644
--- a/gxml/Makefile.am
+++ b/gxml/Makefile.am
@@ -57,17 +57,21 @@ libgxml_0_4_la_SOURCES = \
ProcessingInstruction.vala \
Text.vala \
Serializable.vala \
- Enumeration.vala \
- SerializableObjectModel.vala \
- SerializableJson.vala \
+ jgs/JgsSerializable.vala \
+ jgs/JgsSerialization.vala \
+ xom/XomSerializable.vala \
+ xom/Enumeration.vala \
+ xom/SerializableObjectModel.vala \
+ xom/SerializableJson.vala \
Serialization.vala \
- SerializableGeeTreeMap.vala \
- SerializableGeeHashMap.vala \
- SerializableMapKey.vala \
- SerializableGeeDualKeyMap.vala \
- SerializableMapDualKey.vala \
- SerializableGeeArrayList.vala \
- SerializableContainer.vala
+ xom/XomSerialization.vala \
+ xom/SerializableGeeTreeMap.vala \
+ xom/SerializableGeeHashMap.vala \
+ xom/SerializableMapKey.vala \
+ xom/SerializableGeeDualKeyMap.vala \
+ xom/SerializableMapDualKey.vala \
+ xom/SerializableGeeArrayList.vala \
+ xom/SerializableContainer.vala
gxml_0_4_la_vala.stamp: $(libgxml_0_4_la_SOURCES)
diff --git a/gxml/jgs/JgsSerializable.vala b/gxml/jgs/JgsSerializable.vala
new file mode 100644
index 0000000..a47d974
--- /dev/null
+++ b/gxml/jgs/JgsSerializable.vala
@@ -0,0 +1,363 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* 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
+ * 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>
+ */
+
+
+/*
+ Version 3: json-glib version
+
+ PLAN:
+ * add support for GObject Introspection to allow us to serialise non-property members
+
+ json-glib
+ * has functions to convert XML structures into Objects and vice versa
+ * can convert simple objects automatically
+ * richer objects need to implement interface
+
+ json_serializable_real_serialize -> json_serialize_pspec
+ * how do these get used with GInterfaces? are these default methods like with superclasses?
+ * TODO: I don't think vala does multiple inheritance, so do we want GXml.Serializable to be an interface
or a superclass?
+
+ json_serializable_default_{de,}serialize_property -> json_serializable_real_{de,}serialize
+
+ json_serializable_{de,}serialize_property -> iface->{de,}serialize_property
+ these all get init'd to -> json_serializable_real_{de,}serialize_property
+ these all call -> json_{de,}serialize_pspec
+
+ json_serializable_{find,list,get,set}_propert{y,ies} -> iface->{find,list,get,set}_propert{y,ies}
+ these all get init'd to -> json_serializable_real_{find,list,get,set}_propert{y,ies}
+ these all call -> g_object_{class,}_{find,list,get,set}_propert{y,ies}
+ */
+
+using GXml;
+
+namespace GXml.Jgs {
+ /**
+ * Interface allowing implementors direct control over serialisation of properties and other data
+ *
+ * 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. You can also create virtual properties from
+ * non-public property fields to enable their serialization.
+ *
+ * For an example, look in tests/XmlSerializableTest
+ */
+ public interface Serializable : GLib.Object, GXml.Serializable {
+ /**
+ * Handles serializing potential tasks beyond
+ * serializing individual properties.
+ *
+ * { link doc} is the { link GXml.Document} that will
+ * ultimately contain the serialized object. You can
+ * use it to create the { link GXml.Node}s you want to
+ * add from here to the serialized object, like
+ * { link GXml.Element}s, { link GXml.DocumentFragment}s,
+ * and { link GXml.Text}s. Return your completed XML
+ * structure as a { link GXml.Node} and it will be
+ * added to an <Object> element in the serialized XML.
+ *
+ * Example:
+ *
+ * Say we have a { link GLib.Object}, Cookie, which
+ * looks like this in Vala,
+ *
+ * {{{
+ * class Cookie {
+ * string flavour {}
+ * int mass {}
+ * }
+ * }}}
+ *
+ * The default serialized XML might look like this
+ *
+ * {{{
+ * <Object otype="Cookie" oid="0xC00C1E5">
+ * <Property ptype="gchar*" pname="flavour">Chocolate chip</Property>
+ * <Property ptype="int" pname="mass">28</Property>
+ * </Object>
+ * }}}
+ *
+ * If we want additional information not connected to
+ * any of the properties, we could extend the Cookie
+ * class like this:
+ *
+ * {{{
+ * class Cookie : Serializable {
+ * string flavour {}
+ * int mass {}
+ * public override Node? serialize (Document doc)
+ * throws SerializationError {
+ * return doc.create_comment ("<!-- baked on Nov 16 2013 by Wallace Wells -->");
+ * }
+ * }}}
+ *
+ * This would result in the following serialized XML:
+ *
+ * {{{
+ * <Object otype="Cookie" oid="0xC00C1E5">
+ * <!-- baked on Nov 16 2013 by Wallace Wells -->
+ * <Property ptype="gchar*" pname="flavour">Chocolate chip</Property>
+ * <Property ptype="int" pname="mass">28</Property>
+ * </Object>
+ * }}}
+ *
+ * If you want to completely handle serialization of
+ * your object yourself in { link Serializable.serialize},
+ * you can prevent automatic serialization of properties
+ * by overriding { link Serializable.serialize_property}
+ * and simply returning true.
+ *
+ * @param doc The { link GXml.Document} that contains serialized XML, used to create new {
link GXml.Node}s
+ *
+ * @return A { link GXml.Node} representing serialized content from the implementing object
+ */
+ public virtual GXml.Node?
+ serialize (GXml.Document doc) {
+ return null;
+ }
+
+ /**
+ * 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.Node} that encapsulates the property.
+ * { link GXml.Serialization} will embed the { link GXml.Node} into
+ * a "Property" { link GXml.Element}, so the { link GXml.Node}
+ * 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 itself.
+ *
+ * @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.Node} should belong to
+ *
+ * @return a new { link GXml.Node}, or %NULL
+ */
+ public virtual GXml.Node?
+ serialize_property (string property_name,
+ GLib.ParamSpec spec,
+ GXml.Document doc) {
+ return null;
+ }
+
+ /**
+ * Handle deserialization of an object beyond its
+ * properties.
+ *
+ * This can cover deserialization tasks outside of
+ * just properties, like initialising variables
+ * normally handled by a constructor. (Note that when
+ * deserializing, an object's constructor is not
+ * called.)
+ *
+ * @param serialized_node The XML representation of this object
+ */
+ public virtual void
+ deserialize (GXml.Node serialized_node) {
+ return;
+ }
+
+ /* TODO: consider making the visibility of all of
+ * these interface virtual methods to protected or
+ * internal. In theory, only Serialization should
+ * need to actually see them.
+ */
+
+ /**
+ * 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.
+ *
+ * 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.Node} 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,
+ GLib.ParamSpec spec,
+ GXml.Node property_node) {
+ return false; // default deserialize_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 ();
+ }
+
+ /*
+ * 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/jgs/JgsSerialization.vala
similarity index 51%
rename from gxml/Serialization.vala
rename to gxml/jgs/JgsSerialization.vala
index f90ff54..4a5fa0a 100644
--- a/gxml/Serialization.vala
+++ b/gxml/jgs/JgsSerialization.vala
@@ -48,29 +48,17 @@ namespace GXml {
*/
public errordomain SerializationError {
/**
- * An unknown { link GLib.Type} was encountered.
+ * An object without a known { link GLib.Type} was encountered.
*/
UNKNOWN_TYPE,
/**
- * A property was described in XML that is not known { link GLib.Type}.
+ * A property was described in XML that is not known to the object's type.
*/
UNKNOWN_PROPERTY,
/**
- * Serialization/Deserialization is unsupported for given object type
+ * An object with a known { link GLib.Type} that we do not support was encountered.
*/
- 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
+ UNSUPPORTED_TYPE
}
/**
@@ -99,11 +87,7 @@ namespace GXml {
* { 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
- {
+ private static GXml.Node serialize_property (GLib.Object object, ParamSpec prop_spec,
GXml.Document doc) throws SerializationError {
Type type;
Value value;
Node value_node;
@@ -128,13 +112,21 @@ namespace GXml {
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);
+ if (serializable != null) {
+ serializable.get_property (prop_spec, ref value);
+ } else {
+ 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);
+ if (serializable != null) {
+ serializable.get_property (prop_spec, ref value);
+ } else {
+ 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 ());
@@ -160,27 +152,30 @@ namespace GXml {
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));
+ && ! type.is_a (typeof (Gee.Collection))) {
+ GLib.Object child_object;
+
+ // TODO: this is going to get complicated
+ value = Value (typeof (GLib.Object));
+ if (serializable != null) {
+ serializable.get_property (prop_spec, ref value);
+ } else {
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?
-
- value_node = doc.copy_node (value_doc.document_element);
+
(/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?
+
+ 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
());
+ throw new SerializationError.UNSUPPORTED_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;
@@ -210,68 +205,82 @@ namespace GXml {
* @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
- {
+ public static GXml.Document serialize_object (GLib.Object object) throws SerializationError {
Document doc;
Element root;
ParamSpec[] prop_specs;
Element prop;
+ Serializable serializable = null;
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");
+ Serialization.init_caches ();
+
+ try {
+ /* 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 ();
+
+ // 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.get_type ().is_a (typeof (Serializable))) {
+ serializable = (Serializable)object;
+ }
+
+ root = doc.create_element ("Object");
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);
+ // 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")] */
+ if (serializable != null) {
+ prop_specs = serializable.list_properties ();
+ } else {
+ 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 = null;
+ if (serializable != null) {
+ value_prop = serializable.serialize_property (prop_spec.name,
prop_spec, doc);
+ }
+ if (value_prop == null) {
+ value_prop = Serialization.serialize_property (object,
prop_spec, doc);
+ }
+
+ prop.append_child (value_prop);
+ root.append_child (prop);
+ }
+ } catch (GLib.Error e) {
+ GLib.error ("%s", e.message);
+ // TODO: handle this better
}
/* Debug output */
@@ -289,39 +298,63 @@ namespace GXml {
* 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
- {
+ private static void deserialize_property (ParamSpec spec, Element prop_elem, out Value val)
throws SerializationError {
Type type;
+
type = spec.value_type;
+
+ // if (false || ptype != "") {
+ // // TODO: undisable if we support fields at some point
+ // type = Type.from_name (ptype);
+ // if (type == 0) {
+ // /* This probably shouldn't happen while we're using
+ // ParamSpecs but if we support non-property fields
+ // later, it might be necessary again :D */
+ // throw new SerializationError.UNKNOWN_TYPE ("Deserializing object '%s'
has property '%s' with unknown type '%s'", otype, pname, ptype);
+ // }
+ // }
+
// Get value and save this all as a parameter
+ bool transformed = false;
val = Value (type);
if (GLib.Value.type_transformable (type, typeof (string))) {
- Serializable.string_to_gvalue (prop_elem.content, ref val);
+ try {
+ string_to_gvalue (prop_elem.content, ref val);
+ transformed = true;
+ } catch (SerializationError e) {
+ throw new SerializationError.UNSUPPORTED_TYPE ("string_to_gvalue
should transform it but failed");
+ }
+ // } else if (type.is_a (typeof (Gee.Collection))) {
} 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);
+
+ try {
+ property_object = Serialization.deserialize_object (prop_elem_child);
+ val.set_object (property_object);
+ transformed = true;
+ } catch (GXml.SerializationError e) {
+ // We don't want this one caught by deserialize_object, or we'd have
a cascading error message. Hmm, not so bad if it does, though.
+ e.message += "\nXML [%s]".printf (prop_elem.to_string ());
+ throw e;
+ }
+ }
+
+ if (transformed == false) {
+ throw new SerializationError.UNSUPPORTED_TYPE ("Failed to transform property
from string to type.");
}
}
- /**
- * 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!!!!*/
+ * find make it more unique than just the memory address. */
private static HashTable<string,Object> deserialize_cache = null;
private static HashTable<string,GXml.Node> serialize_cache = null;
// public so that tests can call it
@@ -352,27 +385,10 @@ namespace GXml {
* 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
+ * @param doc { link GXml.Document} representing a { link GLib.Object}
* @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
- {
+ public static GLib.Object deserialize_object (GXml.Node node) throws SerializationError {
Element obj_elem;
string otype;
string oid;
@@ -380,10 +396,14 @@ namespace GXml {
Object obj;
unowned ObjectClass obj_class;
ParamSpec[] specs;
+ Serializable serializable = null;
- obj_elem = (Element)obj_node;
+ if (node.get_type ().is_a (typeof (GXml.Document))) {
+ obj_elem = (node as GXml.Document).document_element as GXml.Element;
+ } else {
+ obj_elem = node as GXml.Element;
+ }
- // FIXME: Remove cache.
// If the object has been deserialised before, get it from cache
oid = obj_elem.get_attribute ("oid");
Serialization.init_caches ();
@@ -396,13 +416,7 @@ namespace GXml {
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;
+ throw new SerializationError.UNKNOWN_TYPE ("Deserializing object claims
unknown type '%s'", otype);
}
// Get the list of properties as ParamSpecs
@@ -411,29 +425,177 @@ namespace GXml {
// 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 ();
+
+ if (type.is_a (typeof (Serializable))) {
+ serializable = (Serializable)obj;
+ }
+
+ if (serializable != null) {
+ specs = serializable.list_properties ();
+ } else {
+ specs = obj_class.list_properties ();
+ }
+
+ SerializationError err = null;
foreach (Node child_node in obj_elem.child_nodes) {
if (child_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
ParamSpec? spec = null;
- spec = obj_class.find_property (pname);
+ if (serializable != null) {
+ spec = serializable.find_property (pname);
+ } else {
+ 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;
+ err = new SerializationError.UNKNOWN_PROPERTY ("Deserializing
object of type '%s' claimed unknown property named '%s'\nXML [%s]", otype, pname, obj_elem.to_string ());
+ break;
+ }
+
+ try {
+ bool serialized = false;
+
+ if (serializable != null) {
+ serialized = serializable.deserialize_property
(spec.name, /* out val, */ spec, prop_elem); // TODO: consider rearranging these or the ones in Serializer to
match
+ }
+ if (!serialized) {
+ Serialization.deserialize_property (spec, prop_elem,
out val);
+ if (serializable != null) {
+ serializable.set_property (spec, val);
+ } else {
+ obj.set_property (pname, val);
+ }
+ /* TODO: should we make a note that for implementing
{get,set}_property in
+ the interface, they should specify override (in
Vala)? What about in C?
+ Need to test which one gets called in which
situations (yeah, already read
+ the tutorial) */
+ }
+ } catch (SerializationError.UNSUPPORTED_TYPE e) {
+ err = new SerializationError.UNSUPPORTED_TYPE ("Cannot
deserialize object '%s's property '%s' with type '%s/%s': %s\nXML [%s]", otype, spec.name,
spec.value_type.name (), spec.value_type.to_string (), e.message, obj_elem.to_string ());
+ break;
}
- Serialization.deserialize_property (spec, prop_elem, out val);
- obj.set_property (pname, val);
}
}
+
+ // TODO: should make a test to ensure this works
+ if (err != null) {
+ Serialization.deserialize_cache.remove (oid);
+ throw err;
+ }
+
return obj;
}
+
+ /* 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 #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);
+ 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_schar ((int8)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 SerializationError.UNSUPPORTED_TYPE ("%s/%s", t.name (),
t.to_string ());
+ }
+ }
}
}
diff --git a/gxml/Enumeration.vala b/gxml/xom/Enumeration.vala
similarity index 99%
rename from gxml/Enumeration.vala
rename to gxml/xom/Enumeration.vala
index b86f957..d375b60 100644
--- a/gxml/Enumeration.vala
+++ b/gxml/xom/Enumeration.vala
@@ -22,7 +22,7 @@
using GXml;
-namespace GXml {
+namespace GXml.Xom {
public class Enumeration
{
/**
diff --git a/gxml/SerializableContainer.vala b/gxml/xom/SerializableContainer.vala
similarity index 88%
rename from gxml/SerializableContainer.vala
rename to gxml/xom/SerializableContainer.vala
index f17dc7a..1e97fd7 100644
--- a/gxml/SerializableContainer.vala
+++ b/gxml/xom/SerializableContainer.vala
@@ -23,7 +23,7 @@
* Any class having a collection managed list of nodes must implement this
* abstract class.
*/
-public abstract class GXml.SerializableContainer : SerializableObjectModel
+public abstract class GXml.Xom.SerializableContainer : SerializableObjectModel
{
/* Xom interface properties */
public abstract void init_containers ();
@@ -32,7 +32,7 @@ public abstract class GXml.SerializableContainer : SerializableObjectModel
/**
* Fake interface to be implemented by any collection.
*/
-public interface GXml.SerializableCollection : Object, Serializable
+public interface GXml.Xom.SerializableCollection : Object, Serializable
{
public virtual bool is_collection () { return true; }
}
diff --git a/gxml/SerializableGeeArrayList.vala b/gxml/xom/SerializableGeeArrayList.vala
similarity index 97%
rename from gxml/SerializableGeeArrayList.vala
rename to gxml/xom/SerializableGeeArrayList.vala
index 4ca42a6..da2593d 100644
--- a/gxml/SerializableGeeArrayList.vala
+++ b/gxml/xom/SerializableGeeArrayList.vala
@@ -22,7 +22,7 @@
using GXml;
using Gee;
-public class GXml.SerializableArrayList<G> : Gee.ArrayList<G>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableArrayList<G> : Gee.ArrayList<G>, Serializable, SerializableCollection
{
protected ParamSpec[] properties { get; set; }
public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableGeeDualKeyMap.vala b/gxml/xom/SerializableGeeDualKeyMap.vala
similarity index 98%
rename from gxml/SerializableGeeDualKeyMap.vala
rename to gxml/xom/SerializableGeeDualKeyMap.vala
index 667bdfe..99d9965 100644
--- a/gxml/SerializableGeeDualKeyMap.vala
+++ b/gxml/xom/SerializableGeeDualKeyMap.vala
@@ -22,7 +22,7 @@
using GXml;
using Gee;
-public class GXml.SerializableDualKeyMap<P,S,V> : Object, Serializable, SerializableCollection
+public class GXml.Xom.SerializableDualKeyMap<P,S,V> : Object, Serializable, SerializableCollection
{
protected Gee.HashMultiMap<P,HashMap<S,V>> storage;
diff --git a/gxml/SerializableGeeHashMap.vala b/gxml/xom/SerializableGeeHashMap.vala
similarity index 97%
rename from gxml/SerializableGeeHashMap.vala
rename to gxml/xom/SerializableGeeHashMap.vala
index a7ce625..b1b290c 100644
--- a/gxml/SerializableGeeHashMap.vala
+++ b/gxml/xom/SerializableGeeHashMap.vala
@@ -21,7 +21,7 @@
*/
using GXml;
-public class GXml.SerializableHashMap<K,V> : Gee.HashMap<K,V>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableHashMap<K,V> : Gee.HashMap<K,V>, Serializable, SerializableCollection
{
protected ParamSpec[] properties { get; set; }
public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableGeeTreeMap.vala b/gxml/xom/SerializableGeeTreeMap.vala
similarity index 97%
rename from gxml/SerializableGeeTreeMap.vala
rename to gxml/xom/SerializableGeeTreeMap.vala
index 4f3efd2..2f5d409 100644
--- a/gxml/SerializableGeeTreeMap.vala
+++ b/gxml/xom/SerializableGeeTreeMap.vala
@@ -21,7 +21,7 @@
*/
using GXml;
-public class GXml.SerializableTreeMap<K,V> : Gee.TreeMap<K,V>, Serializable, SerializableCollection
+public class GXml.Xom.SerializableTreeMap<K,V> : Gee.TreeMap<K,V>, Serializable, SerializableCollection
{
protected ParamSpec[] properties { get; set; }
public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
diff --git a/gxml/SerializableJson.vala b/gxml/xom/SerializableJson.vala
similarity index 99%
rename from gxml/SerializableJson.vala
rename to gxml/xom/SerializableJson.vala
index 376776a..cf0ee3e 100644
--- a/gxml/SerializableJson.vala
+++ b/gxml/xom/SerializableJson.vala
@@ -60,7 +60,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 GXml.Xom.SerializableJson : GLib.Object, Serializable
{
/* Serializable Interface properties */
protected ParamSpec[] properties { get; set; }
diff --git a/gxml/SerializableMapDualKey.vala b/gxml/xom/SerializableMapDualKey.vala
similarity index 94%
rename from gxml/SerializableMapDualKey.vala
rename to gxml/xom/SerializableMapDualKey.vala
index 5bfbf94..93b30c3 100644
--- a/gxml/SerializableMapDualKey.vala
+++ b/gxml/xom/SerializableMapDualKey.vala
@@ -20,7 +20,7 @@
* Daniel Espinosa <esodan gmail com>
*/
using GXml;
-public interface GXml.SerializableMapDualKey<P,S> : Object
+public interface GXml.Xom.SerializableMapDualKey<P,S> : Object
{
public abstract P get_map_primary_key ();
public abstract S get_map_secondary_key ();
diff --git a/gxml/SerializableMapKey.vala b/gxml/xom/SerializableMapKey.vala
similarity index 94%
rename from gxml/SerializableMapKey.vala
rename to gxml/xom/SerializableMapKey.vala
index 944b1b0..a51403a 100644
--- a/gxml/SerializableMapKey.vala
+++ b/gxml/xom/SerializableMapKey.vala
@@ -21,7 +21,7 @@
*/
using GXml;
-public interface GXml.SerializableMapKey<K> : Object
+public interface GXml.Xom.SerializableMapKey<K> : Object
{
public abstract K get_map_key ();
}
diff --git a/gxml/xom/SerializableObjectModel.vala b/gxml/xom/SerializableObjectModel.vala
new file mode 100644
index 0000000..c3feb0e
--- /dev/null
+++ b/gxml/xom/SerializableObjectModel.vala
@@ -0,0 +1,383 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
+/* ObjectModel.vala
+ *
+ * Copyright (C) 2013, 2014 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>
+ */
+
+namespace GXml.Xom {
+ public abstract class SerializableObjectModel : Object, GXml.Serializable, Serializable
+ {
+ /* Serializable interface properties */
+ protected ParamSpec[] properties { get; set; }
+ public GLib.HashTable<string,GLib.ParamSpec> ignored_serializable_properties { get; protected set; }
+ public string? serialized_xml_node_value { get; protected set; default=null; }
+ public virtual bool get_enable_unknown_serializable_property () { return false; }
+ public GLib.HashTable<string,GXml.Node> unknown_serializable_property { get; protected set; }
+
+ public virtual bool serialize_use_xml_node_value () { return false; }
+ public virtual bool property_use_nick () { return false; }
+
+ public virtual string node_name ()
+ {
+ return default_node_name ();
+ }
+ public string default_node_name ()
+ {
+ return get_type().name().down();
+ }
+
+ public virtual GLib.ParamSpec? find_property_spec (string property_name)
+ {
+ return default_find_property_spec (property_name);
+ }
+
+ public virtual void init_properties ()
+ {
+ default_init_properties ();
+ }
+
+ public virtual GLib.ParamSpec[] list_serializable_properties ()
+ {
+ return default_list_serializable_properties ();
+ }
+
+ public virtual void get_property_value (GLib.ParamSpec spec, ref Value val)
+ {
+ default_get_property_value (spec, ref val);
+ }
+
+ public virtual void set_property_value (GLib.ParamSpec spec, GLib.Value val)
+ {
+ default_set_property_value (spec, val);
+ }
+
+ public virtual bool transform_from_string (string str, ref GLib.Value dest)
+ {
+ return false;
+ }
+
+ public virtual bool transform_to_string (GLib.Value val, ref string str)
+ {
+ return false;
+ }
+
+ public virtual GXml.Node? serialize (GXml.Node node)
+ throws GLib.Error
+ requires (node_name () != null)
+ requires (node is Document || node is Element)
+ {
+ return default_serialize (node);
+ }
+
+ public GXml.Node? default_serialize (GXml.Node node) throws GLib.Error
+ {
+#if DEBUG
+ stdout.printf (@"$(get_type ().name ()): Serializing on node: $(node.node_name)\n");
+#endif
+ Document doc;
+ if (node is Document)
+ doc = (Document) node;
+ else
+ doc = node.owner_document;
+ var element = doc.create_element (node_name ());
+ foreach (ParamSpec spec in list_serializable_properties ()) {
+ serialize_property (element, spec);
+ }
+ if (get_enable_unknown_serializable_property ()) {
+ foreach (Node n in unknown_serializable_property.get_values ()) {
+ if (n is Element) {
+ var e = (Node) doc.create_element (n.node_name);
+ n.copy (ref e, true);
+ element.append_child (e);
+ }
+ if (n is Attr) {
+ element.set_attribute (n.node_name, n.node_value);
+ var a = (Node) element.get_attribute_node (n.node_name);
+ n.copy (ref a);
+ }
+ if (n is Text) {
+ var tnode = doc.create_text_node (n.node_value);
+ element.append_child (tnode);
+ }
+ }
+ }
+ // Setting element content
+ if (serialize_use_xml_node_value ()) {
+ // Set un empty string if no value is set for node contents
+ string t = "";
+ if (serialized_xml_node_value != null)
+ t = serialized_xml_node_value;
+ var tn = doc.create_text_node (t);
+#if DEBUG
+ stdout.printf (@"SETTING CONTENT FOR: $(get_type ().name ()): $(element.node_name): content
'$t'\n");
+#endif
+ element.append_child (tn);
+ }
+
+ node.append_child (element);
+ return element;
+ }
+
+ public virtual GXml.Node? serialize_property (GXml.Element element,
+ GLib.ParamSpec prop)
+ throws GLib.Error
+ {
+ return default_serialize_property (element, prop);
+ }
+ public GXml.Node? default_serialize_property (GXml.Element element,
+ GLib.ParamSpec prop)
+ throws GLib.Error
+ {
+ if (prop.value_type.is_a (typeof (Serializable)))
+ {
+ var v = Value (typeof (Object));
+ get_property (prop.name, ref v);
+ var obj = (Serializable) v.get_object ();
+ if (obj != null)
+ return obj.serialize (element);
+ }
+ Value oval;
+ if (prop.value_type.is_a (Type.ENUM))
+ oval = Value (typeof (int));
+ else
+ oval = Value (prop.value_type);
+ get_property (prop.name, ref oval);
+ string val = "";
+ if (prop.value_type.is_a (Type.ENUM)) {
+ try {
+ val = Enumeration.get_nick_camelcase (prop.value_type, oval.get_int ());
+ } catch (EnumerationError e) { val = null; }
+ }
+ else
+ {
+ if (!transform_to_string (oval, ref val)) {
+ if (Value.type_transformable (prop.value_type, typeof (string)))
+ {
+ Value rval = Value (typeof (string));
+ oval.transform (ref rval);
+ val = rval.dup_string ();
+ }
+ else {
+ Node node = null;
+ this.serialize_unknown_property (element, prop, out node);
+ return node;
+ }
+ }
+ }
+ string attr_name;
+ if (property_use_nick () &&
+ prop.get_nick () != null &&
+ prop.get_nick () != "")
+ attr_name = prop.get_nick ();
+ else
+ attr_name = prop.get_name ();
+ var attr = element.get_attribute_node (attr_name);
+ if (attr == null) {
+ if (val != null)
+ element.set_attribute (attr_name, val);
+ }
+ else
+ attr.value = val;
+ return (Node) attr;
+ }
+
+ public virtual GXml.Node? deserialize (GXml.Node node)
+ throws GLib.Error
+ requires (node_name () != null)
+ {
+ return default_deserialize (node);
+ }
+ public GXml.Node? default_deserialize (GXml.Node node)
+ throws GLib.Error
+ {
+ 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 != null, null);
+ if (node_name () == null) {
+ message (@"WARNING: Object type '$(get_type ().name ())' have no Node Name defined");
+ return null;
+ }
+#if DEBUG
+ if (element.node_name.down () != node_name ().down ()) {
+ GLib.warning (@"Actual node's name is '$(element.node_name.down ())' expected '$(node_name
().down ())'");
+ }
+ stdout.printf (@"Deserialize Node: $(element.node_name)\n");
+ stdout.printf (@"Node is: $(element)\n\n");
+ stdout.printf (@"Attributes in Node: $(element.node_name)\n");
+#endif
+ foreach (Attr attr in element.attributes.get_values ())
+ {
+ deserialize_property (attr);
+ }
+#if DEBUG
+ stdout.printf (@"Elements Nodes in Node: $(element.node_name)\n");
+#endif
+ if (element.has_child_nodes ())
+ {
+ if (get_type ().is_a (typeof (SerializableContainer)))
+ {
+// stdout.printf (@"This is a Container: found a: $(get_type ().name ())\n");
+ ((SerializableContainer) this).init_containers ();
+ }
+ var cnodes = new Gee.HashMap<string,ParamSpec> ();
+ foreach (ParamSpec spec in list_serializable_properties ())
+ {
+ if (spec.value_type.is_a (typeof (Serializable)))
+ {
+ if (spec.value_type.is_a (typeof (SerializableCollection)))
+ {
+ Value vo = Value (spec.value_type);
+ get_property (spec.name, ref vo);
+ var objv = vo.get_object ();
+ if (objv != null) {
+ ((Serializable) objv).deserialize (element);
+ cnodes set (((Serializable) objv).node_name (), spec);
+// stdout.printf (@"Added Key for container node as: $(((Serializable) objv).node_name
())\n");
+ }
+ }
+ }
+ }
+ foreach (Node n in element.child_nodes)
+ {
+ if (n is Text) {
+ if (serialize_use_xml_node_value ()) {
+ serialized_xml_node_value = n.node_value;
+#if DEBUG
+ stdout.printf (@"$(get_type ().name ()): NODE '$(element.node_name)' CONTENT
'$(n.node_value)'\n");
+#endif
+ } else {
+ if (get_enable_unknown_serializable_property ()) {
+ if (n.node_value._chomp () == n.node_value && n.node_value != "")
+ unknown_serializable_property.set (n.node_name, n);
+ }
+ }
+ }
+ if (n is Element && !cnodes.has_key (n.node_name)) {
+#if DEBUG
+ stdout.printf (@"$(get_type ().name ()): DESERIALIZING ELEMENT '$(n.node_name)'\n");
+#endif
+ deserialize_property (n);
+ }
+ }
+ }
+ return null;
+ }
+
+ public virtual bool deserialize_property (GXml.Node property_node)
+ throws GLib.Error
+ {
+ return default_deserialize_property (property_node);
+ }
+ public bool default_deserialize_property (GXml.Node property_node)
+ throws GLib.Error
+ {
+#if DEBUG
+ stdout.printf (@"Deserialize Property Node: $(property_node.node_name)\n");
+#endif
+ bool ret = false;
+ var prop = find_property_spec (property_node.node_name);
+ if (prop == null) {
+ // FIXME: Event emit
+ if (get_enable_unknown_serializable_property ()) {
+// stdout.printf (@"Adding node $(property_node.node_name) to $(get_type ().name ())\n");
+ unknown_serializable_property.set (property_node.node_name, property_node);
+ }
+ return true;
+ }
+ if (prop.value_type.is_a (typeof (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;
+ if (prop.value_type == Type.ENUM)
+ val = Value (typeof (int));
+ else
+ val = Value (prop.value_type);
+ if (property_node is GXml.Attr)
+ {
+ if (prop.value_type.is_a (Type.ENUM)) {
+ EnumValue env;
+ try {
+ env = Enumeration.parse (prop.value_type, property_node.node_value);
+ val.set_enum (env.value);
+ }
+ catch (EnumerationError e) {}
+ }
+ else {
+ if (!transform_from_string (property_node.node_value, ref val)) {
+ 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) {
+ Value apval = Value (p.value_type);
+ ((Serializable)a).get_property_value (p, ref apval);
+ Value bpval = Value (bp.value_type);;
+ ((Serializable)b).get_property_value (bp, ref bpval);
+ if ( apval != bpval)
+ ret = false;
+ }
+ }
+ return ret;
+ }
+ return false;
+ }
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]