[json-glib] gobject: Support constructor properties



commit 83dea3b3dd2281dca206e0873b5fed0a2a3d50de
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Oct 27 14:01:24 2009 +0000

    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.

 json-glib/json-gobject.c    |   98 ++++++++++++++++++++++++++++++++++++++-----
 tests/test-serialize-full.c |   11 +++--
 2 files changed, 93 insertions(+), 16 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 (&param.value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+      val = json_object_get_member (object, member_name);
+      res = json_deserialize_pspec (&param.value, pspec, val);
+      if (!res)
+        g_value_unset (&param.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 (&param->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;
     }
 
diff --git a/tests/test-serialize-full.c b/tests/test-serialize-full.c
index 443b41f..7c42dbd 100644
--- a/tests/test-serialize-full.c
+++ b/tests/test-serialize-full.c
@@ -297,7 +297,8 @@ test_object_class_init (TestObjectClass *klass)
                                    PROP_BAR,
                                    g_param_spec_boolean ("bar", "Bar", "Bar",
                                                          FALSE,
-                                                         G_PARAM_READWRITE));
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property (gobject_class,
                                    PROP_BAZ,
                                    g_param_spec_string ("baz", "Baz", "Baz",
@@ -330,7 +331,7 @@ static void
 test_object_init (TestObject *object)
 {
   object->foo = 0;
-  object->bar = TRUE;
+  object->bar = FALSE;
   object->baz = NULL; 
 
   object->blah.foo = object->foo;
@@ -346,7 +347,7 @@ test_object_init (TestObject *object)
 static const gchar *var_test =
 "{\n"
 "  \"foo\"  : 42,\n"
-"  \"bar\"  : false,\n"
+"  \"bar\"  : true,\n"
 "  \"baz\"  : \"hello\",\n"
 "  \"meh\"  : \"baz\",\n"
 "  \"mah\"  : [ \"hello\", \", \", \"world\", \"!\" ],\n"
@@ -377,12 +378,12 @@ test_deserialize (void)
              " baz: %s\n"
              " meh: %s\n",
              TEST_OBJECT (object)->foo == 42            ? "<true>" : "<false>",
-             TEST_OBJECT (object)->bar == FALSE         ? "<true>" : "<false>",
+             TEST_OBJECT (object)->bar == TRUE          ? "<true>" : "<false>",
              TEST_OBJECT (object)->baz != NULL          ? "<true>" : "<false>",
              TEST_OBJECT (object)->meh == TEST_ENUM_BAZ ? "<true>" : "<false>");
 
   g_assert_cmpint (TEST_OBJECT (object)->foo, ==, 42);
-  g_assert_cmpint (TEST_OBJECT (object)->bar, ==, FALSE);
+  g_assert_cmpint (TEST_OBJECT (object)->bar, ==, TRUE);
   g_assert_cmpstr (TEST_OBJECT (object)->baz, ==, "hello");
   g_assert_cmpint (TEST_OBJECT (object)->meh, ==, TEST_ENUM_BAZ);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]