summaryrefslogtreecommitdiff
path: root/json-glib/json-gobject.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@openedhand.com>2007-11-13 10:51:58 +0000
committerEmmanuele Bassi <ebassi@openedhand.com>2007-11-13 10:51:58 +0000
commitb83a2bfa96885837ca48bacb6492fd68a2b5b564 (patch)
treef1bbc56d1fb13fd508112e018e5e9ebc5aca0c58 /json-glib/json-gobject.c
parent1f9b3e50282f8aa4a421c83ad596f6186ef82ec9 (diff)
parent198ed839424dc7791d22dede152f4d7abc16a8b2 (diff)
downloadjson-glib-b83a2bfa96885837ca48bacb6492fd68a2b5b564.tar.gz
Merge branch 'gobject-deserialize' into work
Diffstat (limited to 'json-glib/json-gobject.c')
-rw-r--r--json-glib/json-gobject.c283
1 files changed, 262 insertions, 21 deletions
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c
index f6f8b57..3357910 100644
--- a/json-glib/json-gobject.c
+++ b/json-glib/json-gobject.c
@@ -129,6 +129,92 @@ json_serializable_deserialize_property (JsonSerializable *serializable,
property_node);
}
+static gboolean
+json_deserialize_pspec (GValue *value,
+ GParamSpec *pspec,
+ JsonNode *node)
+{
+ GValue node_value = { 0, };
+ gboolean retval = FALSE;
+
+ switch (JSON_NODE_TYPE (node))
+ {
+ case JSON_NODE_OBJECT:
+ return FALSE;
+
+ case JSON_NODE_ARRAY:
+ if (G_VALUE_HOLDS (value, G_TYPE_STRV))
+ {
+ JsonArray *array = json_node_get_array (node);
+ guint i, array_len = json_array_get_length (array);
+ GString *buffer = g_string_new (NULL);
+ gchar **strv = NULL;
+
+ for (i = 0; i < array_len; i++)
+ {
+ JsonNode *val = json_array_get_element (array, i);
+
+ if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE)
+ continue;
+
+ if (json_node_get_string (val) != NULL);
+ {
+ g_string_append (buffer, json_node_get_string (val));
+ g_string_append_c (buffer, '\v');
+ }
+ }
+
+ strv = g_strsplit (buffer->str, "\v", -1);
+ g_value_set_boxed (value, strv);
+
+ g_strfreev (strv);
+ g_string_free (buffer, TRUE);
+ retval = TRUE;
+ }
+ break;
+
+ case JSON_NODE_VALUE:
+ json_node_get_value (node, &node_value);
+
+ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ case G_TYPE_DOUBLE:
+ case G_TYPE_STRING:
+ g_value_copy (&node_value, value);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_CHAR:
+ g_value_set_char (value, (gchar) g_value_get_int (&node_value));
+ retval = TRUE;
+ break;
+
+ case G_TYPE_UINT:
+ g_value_set_uint (value, (gint) g_value_get_int (&node_value));
+ retval = TRUE;
+ break;
+
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (value, (guchar) g_value_get_int (&node_value));
+ retval = TRUE;
+ break;
+
+ default:
+ retval = FALSE;
+ break;
+ }
+ break;
+
+ case JSON_NODE_NULL:
+ retval = FALSE;
+ break;
+ }
+
+ return retval;
+}
+
static JsonNode *
json_serialize_pspec (const GValue *real_value,
GParamSpec *pspec)
@@ -136,13 +222,7 @@ json_serialize_pspec (const GValue *real_value,
JsonNode *retval = NULL;
GValue value = { 0, };
- 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_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value)))
{
case G_TYPE_INT:
case G_TYPE_BOOLEAN:
@@ -155,6 +235,11 @@ json_serialize_pspec (const GValue *real_value,
g_value_unset (&value);
break;
+ case G_TYPE_FLOAT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_double (retval, (gdouble) g_value_get_float (real_value));
+ break;
+
case G_TYPE_STRING:
/* strings might be NULL */
if (!g_value_get_string (real_value))
@@ -196,18 +281,32 @@ json_serialize_pspec (const GValue *real_value,
break;
case G_TYPE_UINT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, (gint) g_value_get_uint (real_value));
+ break;
+
case G_TYPE_LONG:
case G_TYPE_ULONG:
+ break;
+
case G_TYPE_CHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, (gint) g_value_get_char (real_value));
+ break;
+
case G_TYPE_UCHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, (gint) g_value_get_uchar (real_value));
+ break;
+
case G_TYPE_ENUM:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_enum (real_value));
+ break;
+
case G_TYPE_FLAGS:
- /* 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);
- json_node_set_value (retval, &value);
- g_value_unset (&value);
+ json_node_set_int (retval, g_value_get_flags (real_value));
break;
case G_TYPE_NONE:
@@ -224,6 +323,139 @@ json_serialize_pspec (const GValue *real_value,
}
/**
+ * json_construct_gobject:
+ * @gtype: the #GType of object to construct
+ * @data: a JSON data stream
+ * @length: length of the data stream, or -1 if it is NUL-terminated
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deserializes a JSON data stream and creates the corresponding
+ * #GObject class. If @gtype implements the #JsonSerializableIface
+ * interface, it will be responsible to deserialize all the JSON
+ * members into the respective properties; otherwise, the default
+ * implementation will be used to translate the compatible JSON
+ * native types.
+ *
+ * Return value: a #GObject or %NULL
+ *
+ * Since: 0.4
+ */
+GObject *
+json_construct_gobject (GType gtype,
+ const gchar *data,
+ gsize length,
+ GError **error)
+{
+ JsonSerializableIface *iface = NULL;
+ JsonSerializable *serializable = NULL;
+ gboolean deserialize_property;
+ JsonParser *parser;
+ JsonNode *root;
+ JsonObject *object;
+ GError *parse_error;
+ GList *members, *l;
+ guint n_members;
+ GObjectClass *klass;
+ GObject *retval;
+
+ g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+
+ if (length < 0)
+ length = strlen (data);
+
+ parser = json_parser_new ();
+
+ parse_error = NULL;
+ json_parser_load_from_data (parser, data, length, &parse_error);
+ if (parse_error)
+ {
+ g_propagate_error (error, parse_error);
+ g_object_unref (parser);
+ return NULL;
+ }
+
+ root = json_parser_get_root (parser);
+ if (JSON_NODE_TYPE (root) != JSON_NODE_OBJECT)
+ {
+ g_set_error (error, JSON_PARSER_ERROR,
+ JSON_PARSER_ERROR_PARSE,
+ "Expecting a JSON object, but the root node "
+ "is of type `%s'",
+ json_node_type_name (root));
+ g_object_unref (parser);
+ return NULL;
+ }
+
+ klass = g_type_class_ref (gtype);
+ retval = g_object_new (gtype, NULL);
+
+ if (g_type_is_a (gtype, JSON_TYPE_SERIALIZABLE))
+ {
+ serializable = JSON_SERIALIZABLE (retval);
+ iface = JSON_SERIALIZABLE_GET_IFACE (serializable);
+ deserialize_property = (iface->deserialize_property != NULL);
+ }
+ else
+ deserialize_property = FALSE;
+
+ object = json_node_get_object (root);
+
+ g_object_freeze_notify (retval);
+
+ n_members = json_object_get_size (object);
+ members = json_object_get_members (object);
+
+ for (l = members; l != NULL; l = l->next)
+ {
+ const gchar *member_name = l->data;
+ GParamSpec *pspec;
+ JsonNode *val;
+ GValue value = { 0, };
+ gboolean res = FALSE;
+
+ pspec = g_object_class_find_property (klass, member_name);
+ if (!pspec)
+ continue;
+
+ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ continue;
+
+ if (!(pspec->flags & G_PARAM_WRITABLE))
+ continue;
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ val = json_object_get_member (object, member_name);
+
+ if (deserialize_property)
+ {
+ res = iface->deserialize_property (serializable, pspec->name,
+ &value,
+ pspec,
+ val);
+ }
+
+ if (!res)
+ res = json_deserialize_pspec (&value, pspec, val);
+
+ if (res)
+ g_object_set_property (retval, pspec->name, &value);
+
+ g_value_unset (&value);
+ }
+
+ g_list_free (members);
+
+ g_object_thaw_notify (retval);
+
+ g_type_class_unref (klass);
+ g_object_unref (parser);
+
+ return retval;
+}
+
+/**
* json_serialize_gobject:
* @gobject: a #GObject
* @length: return value for the length of the buffer, or %NULL
@@ -240,6 +472,8 @@ json_serialize_gobject (GObject *gobject,
gsize *length)
{
JsonSerializableIface *iface = NULL;
+ JsonSerializable *serializable = NULL;
+ gboolean serialize_property = FALSE;
JsonGenerator *gen;
JsonNode *root;
JsonObject *object;
@@ -250,7 +484,11 @@ json_serialize_gobject (GObject *gobject,
g_return_val_if_fail (G_OBJECT (gobject), NULL);
if (JSON_IS_SERIALIZABLE (gobject))
- iface = JSON_SERIALIZABLE_GET_IFACE (gobject);
+ {
+ serializable = JSON_SERIALIZABLE (gobject);
+ iface = JSON_SERIALIZABLE_GET_IFACE (gobject);
+ serialize_property = (iface->serialize_property != NULL);
+ }
object = json_object_new ();
@@ -263,7 +501,7 @@ json_serialize_gobject (GObject *gobject,
{
GParamSpec *pspec = pspecs[i];
GValue value = { 0, };
- JsonNode *node;
+ JsonNode *node = NULL;
/* read only what we can */
if (!(pspec->flags & G_PARAM_READABLE))
@@ -272,15 +510,14 @@ json_serialize_gobject (GObject *gobject,
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
g_object_get_property (gobject, pspec->name, &value);
- if (iface && iface->serialize_property)
+ if (serialize_property)
{
- JsonSerializable *serializable = JSON_SERIALIZABLE (gobject);
-
node = iface->serialize_property (serializable, pspec->name,
&value,
pspec);
}
- else
+
+ if (!node)
node = json_serialize_pspec (&value, pspec);
if (node)
@@ -291,11 +528,15 @@ json_serialize_gobject (GObject *gobject,
g_free (pspecs);
- gen = json_generator_new ();
- json_generator_set_root (gen, root);
- g_object_set (gen, "pretty", TRUE, NULL);
+ gen = g_object_new (JSON_TYPE_GENERATOR,
+ "root", root,
+ "pretty", TRUE,
+ "indent", 2,
+ NULL);
+
data = json_generator_to_data (gen, length);
g_object_unref (gen);
+ json_node_free (root);
return data;
}