summaryrefslogtreecommitdiff
path: root/json-glib/json-gobject.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@openedhand.com>2007-11-10 01:26:46 +0000
committerEmmanuele Bassi <ebassi@openedhand.com>2007-11-10 01:26:46 +0000
commit45c697263364a975fd6a54373f999f2932436b6f (patch)
treed8744258a70d42d4ddd74c77609c65193327df1d /json-glib/json-gobject.c
parent4eade1089355ebcf0614d0cfbc9c441513b7d97a (diff)
downloadjson-glib-45c697263364a975fd6a54373f999f2932436b6f.tar.gz
Initial implementation of GObject deserialization function
The json_construct_gobject() function takes a GType and a JSON data stream and constructs a new instance for the given type. If the type is a JsonSerializable, it will use the JsonSerializable interface for parsing the JsonNodes of each object member. This is the initial implementation of the function: the JsonNode-to-GValue fallback parser is just a stub.
Diffstat (limited to 'json-glib/json-gobject.c')
-rw-r--r--json-glib/json-gobject.c182
1 files changed, 170 insertions, 12 deletions
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c
index f6f8b57..ba5ce5b 100644
--- a/json-glib/json-gobject.c
+++ b/json-glib/json-gobject.c
@@ -129,6 +129,22 @@ json_serializable_deserialize_property (JsonSerializable *serializable,
property_node);
}
+static gboolean
+json_deserialize_pspec (GValue *value,
+ GParamSpec *pspec,
+ JsonNode *node)
+{
+ gboolean retval = FALSE;
+ GValue node_value = { 0, };
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT)
+ {
+ return FALSE;
+ }
+
+ return retval;
+}
+
static JsonNode *
json_serialize_pspec (const GValue *real_value,
GParamSpec *pspec)
@@ -136,13 +152,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 +165,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 +211,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 +253,135 @@ 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;
+ 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);
+ }
+
+ 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;
+
+ 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 (iface && iface->deserialize_property)
+ {
+
+ res = iface->deserialize_property (serializable, pspec->name,
+ &value,
+ pspec,
+ val);
+ }
+ else
+ 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