diff options
author | Emmanuele Bassi <ebassi@openedhand.com> | 2007-10-16 17:40:06 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@openedhand.com> | 2007-10-16 17:40:06 +0100 |
commit | 87a36b8a5e23f3cf80730627f9b89061934a5bbf (patch) | |
tree | 6498512341036877e5b30d5d46a7fd83d2c60254 /json-glib/json-gobject.c | |
parent | 85cb0f44c4c7297a75141999674f3eb0fdf6a308 (diff) | |
download | json-glib-87a36b8a5e23f3cf80730627f9b89061934a5bbf.tar.gz |
Add the JsonSerializable interface
The JsonSerializable interface allows implementations to override the
GObject-to-JSON serialization process, by providing two virtual methods
to control the (de)serialization of GObject properties. This way it's
possible to serialize GObjects with properties holding complex data types.
Diffstat (limited to 'json-glib/json-gobject.c')
-rw-r--r-- | json-glib/json-gobject.c | 188 |
1 files changed, 157 insertions, 31 deletions
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c index ee652aa..d02a7bf 100644 --- a/json-glib/json-gobject.c +++ b/json-glib/json-gobject.c @@ -24,10 +24,12 @@ * JSON-GLib provides API for serializing and deserializing #GObject<!-- -->s * to and from JSON data streams. * - * The simplest form to serialize a #GObject class is calling the - * json_serialize_gobject() function on a #GObject instance: every - * property using a fundamental type (or a type that can be coherced - * into a fundamental type) will be converted into a JSON type. + * Simple #GObject classes can be (de)serialized into JSON objects, if the + * properties have compatible types with the native JSON types (integers, + * booleans, strings, string vectors). If the class to be (de)serialized has + * complex data types for properties (like boxed types or other objects) + * then the class should implement the provided #JsonSerializable interface + * and its virtual functions. */ #include "config.h" @@ -39,47 +41,151 @@ #include "json-parser.h" #include "json-generator.h" +GType +json_serializable_get_type (void) +{ + static GType iface_type = 0; + + return iface_type; +} + +/** + * json_serializable_serialize_property: + * @serializable: a #JsonSerializable object + * @property_name: the name of the property + * @value: the value of the property + * @pspec: a #GParamSpec + * + * Asks a #JsonSerializable implementation to serialize a #GObject + * property into a #JsonNode object. + * + * Return value: a #JsonNode containing the serialize property + */ +JsonNode * +json_serializable_serialize_property (JsonSerializable *serializable, + const gchar *property_name, + const GValue *value, + GParamSpec *pspec) +{ + JsonSerializableIface *iface; + + g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), NULL); + g_return_val_if_fail (property_name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + g_return_val_if_fail (pspec != NULL, NULL); + + iface = JSON_SERIALIZABLE_GET_IFACE (serializable); + if (!iface->serialize_property) + return json_node_new (JSON_NODE_NULL); + + return iface->serialize_property (serializable, property_name, value, pspec); +} + +/** + * json_serializable_deserialize_property: + * @serializable: a #JsonSerializable + * @property_name: the name of the property + * @value: a pointer to an uninitialized #GValue + * @pspec: a #GParamSpec + * @property_node: a #JsonNode containing the serialized property + * + * Asks a #JsonSerializable implementation to deserialize the + * property contained inside @property_node into @value. + * + * Return value: %TRUE if the property was successfully deserialized. + */ +gboolean +json_serializable_deserialize_property (JsonSerializable *serializable, + const gchar *property_name, + GValue *value, + GParamSpec *pspec, + JsonNode *property_node) +{ + JsonSerializableIface *iface; + + g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), FALSE); + g_return_val_if_fail (property_name != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (pspec != NULL, FALSE); + g_return_val_if_fail (property_node != NULL, FALSE); + + iface = JSON_SERIALIZABLE_GET_IFACE (serializable); + if (!iface->deserialize_property) + { + g_param_value_defaults (pspec, value); + return TRUE; + } + + return iface->deserialize_property (serializable, + property_name, + value, + pspec, + property_node); +} + static JsonNode * -json_serialize_pspec (GObject *gobject, - GParamSpec *pspec) +json_serialize_pspec (const GValue *real_value, + GParamSpec *pspec) { JsonNode *retval = NULL; - GValue real_value = { 0, }; GValue value = { 0, }; - g_value_init (&real_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_object_get_property (gobject, pspec->name, &real_value); - - if (!G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&real_value))) + if (!G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value))) { g_warning ("Complex types are not supported."); return NULL; } - switch (G_VALUE_TYPE (&real_value)) + switch (G_VALUE_TYPE (real_value)) { case G_TYPE_INT: case G_TYPE_BOOLEAN: - case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: /* JSON native types */ retval = json_node_new (JSON_NODE_VALUE); - g_value_init (&value, G_VALUE_TYPE (&real_value)); - g_value_copy (&real_value, &value); + g_value_init (&value, G_VALUE_TYPE (real_value)); + g_value_copy (real_value, &value); json_node_set_value (retval, &value); g_value_unset (&value); break; case G_TYPE_STRING: /* strings might be NULL */ - if (!g_value_get_string (&real_value)) + if (!g_value_get_string (real_value)) retval = json_node_new (JSON_NODE_NULL); else { retval = json_node_new (JSON_NODE_VALUE); - g_value_init (&value, G_TYPE_STRING); - g_value_set_string (&value, g_value_get_string (&real_value)); - json_node_set_value (retval, &value); - g_value_unset (&value); + json_node_set_string (retval, g_value_get_string (real_value)); + break; + } + break; + + case G_TYPE_BOXED: + if (G_VALUE_HOLDS (real_value, G_TYPE_STRV)) + { + gchar **strv = g_value_get_boxed (real_value); + gint i, strv_len; + JsonArray *array; + + strv_len = g_strv_length (strv); + array = json_array_sized_new (strv_len); + + for (i = 0; i < strv_len; i++) + { + JsonNode *str = json_node_new (JSON_NODE_VALUE); + + json_node_set_string (str, strv[i]); + json_array_add_element (array, str); + } + + retval = json_node_new (JSON_NODE_ARRAY); + json_node_take_array (retval, array); + } + else + { + g_warning ("Unsupported type `%s'", + g_type_name (G_VALUE_TYPE (real_value))); } break; @@ -93,7 +199,7 @@ json_serialize_pspec (GObject *gobject, /* these should fit into an int */ retval = json_node_new (JSON_NODE_VALUE); g_value_init (&value, G_TYPE_INT); - g_value_copy (&real_value, &value); + g_value_copy (real_value, &value); json_node_set_value (retval, &value); g_value_unset (&value); break; @@ -104,12 +210,10 @@ json_serialize_pspec (GObject *gobject, default: g_warning ("Unsupported type `%s'", - g_type_name (G_VALUE_TYPE (&real_value))); + g_type_name (G_VALUE_TYPE (real_value))); break; } - g_value_unset (&real_value); - return retval; } @@ -118,7 +222,10 @@ json_serialize_pspec (GObject *gobject, * @gobject: a #GObject * @length: return value for the length of the buffer, or %NULL * - * Serializes a #GObject into a JSON data stream. + * Serializes a #GObject into a JSON data stream. If @gobject implements + * the #JsonSerializableIface interface, it will be responsible to + * serizalize all its properties; otherwise, the default implementation + * will be use to translate the compatible types into JSON native types. * * Return value: a JSON data stream representing the passed #GObject */ @@ -126,6 +233,7 @@ gchar * json_serialize_gobject (GObject *gobject, gsize *length) { + JsonSerializableIface *iface = NULL; JsonGenerator *gen; JsonNode *root; JsonObject *object; @@ -133,7 +241,10 @@ json_serialize_gobject (GObject *gobject, guint n_pspecs, i; gchar *data; - g_return_val_if_fail (G_IS_OBJECT (gobject), NULL); + g_return_val_if_fail (G_OBJECT (gobject), NULL); + + if (JSON_IS_SERIALIZABLE (gobject)) + iface = JSON_SERIALIZABLE_GET_IFACE (gobject); object = json_object_new (); @@ -142,19 +253,34 @@ json_serialize_gobject (GObject *gobject, pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (gobject), &n_pspecs); - for (i = 0; i < n_pspecs; i++) { GParamSpec *pspec = pspecs[i]; - JsonNode *value; + GValue value = { 0, }; + JsonNode *node; /* read only what we can */ if (!(pspec->flags & G_PARAM_READABLE)) continue; - value = json_serialize_pspec (gobject, pspec); - if (value) - json_object_add_member (object, pspec->name, value); + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + g_object_get_property (gobject, pspec->name, &value); + + if (iface && iface->serialize_property) + { + JsonSerializable *serializable = JSON_SERIALIZABLE (gobject); + + node = iface->serialize_property (serializable, pspec->name, + &value, + pspec); + } + else + node = json_serialize_pspec (&value, pspec); + + if (node) + json_object_add_member (object, pspec->name, node); + + g_value_unset (&value); } g_free (pspecs); |