diff options
author | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-10 01:26:46 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-10 01:26:46 +0000 |
commit | 45c697263364a975fd6a54373f999f2932436b6f (patch) | |
tree | d8744258a70d42d4ddd74c77609c65193327df1d /json-glib/json-gobject.c | |
parent | 4eade1089355ebcf0614d0cfbc9c441513b7d97a (diff) | |
download | json-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.c | 182 |
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 |