diff options
author | Emmanuele Bassi <ebassi@linux.intel.com> | 2009-10-27 14:01:24 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@linux.intel.com> | 2009-10-27 14:09:43 +0000 |
commit | 83dea3b3dd2281dca206e0873b5fed0a2a3d50de (patch) | |
tree | e0b344ffe7e20accf8c81a037c8e884041efe369 /json-glib/json-gobject.c | |
parent | 2616938c7c042fced9be197205a535a8b420534e (diff) | |
download | json-glib-83dea3b3dd2281dca206e0873b5fed0a2a3d50de.tar.gz |
gobject: Support constructor properties
The GObject deserialization code currently skips all the constructor
and constructor-only properties. In order to implement them we can
add a preliminary pass on the JSON object members and build a
GParameter array.
As we don't have a GObject instance we cannot really use the
Serializable interface to provide custom parsing for complex data
structures, thus we fall back to the default deserialization code
path.
Diffstat (limited to 'json-glib/json-gobject.c')
-rw-r--r-- | json-glib/json-gobject.c | 98 |
1 files changed, 87 insertions, 11 deletions
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c index 1b3b1fe..f10b6a3 100644 --- a/json-glib/json-gobject.c +++ b/json-glib/json-gobject.c @@ -187,14 +187,90 @@ json_gobject_new (GType gtype, JsonSerializableIface *iface = NULL; JsonSerializable *serializable = NULL; gboolean deserialize_property; - GList *members, *l; + GList *members, *members_left, *l; guint n_members; GObjectClass *klass; GObject *retval; + GArray *construct_params; + gint n, i; klass = g_type_class_ref (gtype); - retval = g_object_new (gtype, NULL); + n_members = json_object_get_size (object); + members = json_object_get_members (object); + members_left = NULL; + + /* first pass: construct and construct-only properties; here + * we cannot use Serializable because we don't have an + * instance yet; we use the default implementation of + * json_deserialize_pspec() to deserialize known types + * + * FIXME - find a way to allow deserialization for these + * properties + */ + construct_params = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_members); + + for (l = members; l != NULL; l = l->next) + { + const gchar *member_name = l->data; + GParamSpec *pspec; + GParameter param = { NULL, }; + JsonNode *val; + GValue value = { 0, }; + gboolean res = FALSE; + + pspec = g_object_class_find_property (klass, member_name); + if (!pspec) + goto next_member; + + if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY) || + !(pspec->flags & G_PARAM_CONSTRUCT_ONLY)) + goto next_member; + + if (!(pspec->flags & G_PARAM_WRITABLE)) + goto next_member; + + g_value_init (¶m.value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + + val = json_object_get_member (object, member_name); + res = json_deserialize_pspec (¶m.value, pspec, val); + if (!res) + g_value_unset (¶m.value); + else + { + param.name = g_strdup (pspec->name); + + g_array_append_val (construct_params, param); + + continue; + } + + next_member: + members_left = g_list_prepend (members_left, pspec->name); + } + + retval = g_object_newv (gtype, + construct_params->len, + (GParameter *) construct_params->data); + + /* free the contents of the GArray */ + for (i = 0; i < construct_params->len; i++) + { + GParameter *param = &g_array_index (construct_params, GParameter, i); + + g_free ((gchar *) param->name); + g_value_unset (¶m->value); + } + + g_array_free (construct_params, TRUE); + g_list_free (members); + + /* we use g_list_prepend() above, but we want to maintain + * the ordering of json_object_get_members() here + */ + members = g_list_reverse (members_left); + + /* do the Serializable type check once */ if (g_type_is_a (gtype, JSON_TYPE_SERIALIZABLE)) { serializable = JSON_SERIALIZABLE (retval); @@ -206,9 +282,6 @@ json_gobject_new (GType gtype, 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; @@ -221,7 +294,9 @@ json_gobject_new (GType gtype, if (!pspec) continue; - if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) + /* we should have dealt with these above */ + if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) || + (pspec->flags & G_PARAM_CONSTRUCT)) continue; if (!(pspec->flags & G_PARAM_WRITABLE)) @@ -242,6 +317,9 @@ json_gobject_new (GType gtype, if (!res) res = json_deserialize_pspec (&value, pspec, val); + /* FIXME - we probably want to be able to have a custom + * set_property() for Serializable implementations + */ if (res) g_object_set_property (retval, pspec->name, &value); @@ -492,7 +570,7 @@ json_serialize_pspec (const GValue *real_value, break; case G_TYPE_STRING: - /* strings might be NULL */ + /* strings might be NULL, so we handle it differently */ if (!g_value_get_string (real_value)) retval = json_node_new (JSON_NODE_NULL); else @@ -536,8 +614,7 @@ json_serialize_pspec (const GValue *real_value, } else { - g_warning ("Unsupported type `%s'", - g_type_name (G_VALUE_TYPE (real_value))); + g_warning ("Unsupported type `%s'", g_type_name (G_VALUE_TYPE (real_value))); } break; @@ -595,8 +672,7 @@ json_serialize_pspec (const GValue *real_value, break; default: - g_warning ("Unsupported type `%s'", - g_type_name (G_VALUE_TYPE (real_value))); + g_warning ("Unsupported type `%s'", g_type_name (G_VALUE_TYPE (real_value))); break; } |