implement json child obj deserialization

Sun, 04 Jan 2026 17:45:50 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 04 Jan 2026 17:45:50 +0100
changeset 42
3c989bc611c6
parent 41
daabc9bb5445
child 43
73c1ced3a620

implement json child obj deserialization

dbutils/json.c file | annotate | diff | comparison | revisions
dbutils/json.h file | annotate | diff | comparison | revisions
test/json.c file | annotate | diff | comparison | revisions
test/json.h file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
--- a/dbutils/json.c	Sat Jan 03 18:19:58 2026 +0100
+++ b/dbutils/json.c	Sun Jan 04 17:45:50 2026 +0100
@@ -131,17 +131,25 @@
 
 /* --------------- Json to Obj deserialization functions --------------------*/
 
-void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+static void* jsonToObj(DBUClass *type, const CxAllocator *a, CxJsonValue *value, int depth, int *error) {
     if(!cxJsonIsObject(value)) {
+        *error = 1;
+        return NULL;
+    }
+    if(depth > DBU_JSON_MAX_DEPTH) {
+        *error = 2;
         return NULL;
     }
     if(!a) {
         a = cxDefaultAllocator;
     }
-    
+     
     void *obj = cxMalloc(a, type->obj_size);
     if(obj) {
         memset(obj, 0, type->obj_size);
+    } else {
+        *error = 3;
+        return NULL;
     }
     
     char buf[64];
@@ -151,7 +159,10 @@
     cx_foreach(CxMapEntry *, entry, i) {
         DBUField *field = cxMapGet(type->fields, entry->key);
         if(!field) {
-            continue;
+            field = cxMapGet(type->obj_fields, entry->key);
+            if(!field) {
+                continue;
+            }
         }
         
         len = 0;
@@ -194,13 +205,26 @@
             case CX_JSON_STRING: {
                 cxmutstr str = child->string;
                 if(field->initValue(field, a, obj, str.ptr, str.length)) {
+                    *error = 3;
                     free(obj); // TODO: improve obj cleanup
                     return NULL;
                 }
                 break;
             }
             case CX_JSON_OBJECT: {
-                // TODO
+                if(field->objType && field->initObjValue) {
+                    void *child_obj = jsonToObj(field->objType, a, child, depth+1, error);
+                    if(child_obj) {
+                        field->initObjValue(field, a, obj, child_obj);
+                    } else {
+                        free(obj); // TODO: improve obj cleanup
+                        return NULL;
+                    }
+                } else {
+                    *error = 4;
+                    free(obj); // TODO: improve obj cleanup
+                    return NULL;
+                }
                 break;
             }
             case CX_JSON_ARRAY: {
@@ -214,10 +238,17 @@
             if(field->initValue(field, a, obj, buf, len)) {
                 // TODO: completely cleanup obj
                 free(obj);
+                *error = 3;
                 return NULL;
             }
         }
     }
     
+    *error = 0;
     return obj;
 }
+
+void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+    int error;
+    return jsonToObj(type, a, value, 0, &error);
+}
--- a/dbutils/json.h	Sat Jan 03 18:19:58 2026 +0100
+++ b/dbutils/json.h	Sun Jan 04 17:45:50 2026 +0100
@@ -35,7 +35,7 @@
 extern "C" {
 #endif
 
-
+#define DBU_JSON_MAX_DEPTH 512
 
 
 #ifdef __cplusplus
--- a/test/json.c	Sat Jan 03 18:19:58 2026 +0100
+++ b/test/json.c	Sun Jan 04 17:45:50 2026 +0100
@@ -358,3 +358,26 @@
         free(obj);
     }
 }
+
+CX_TEST(testJsonToObjectWithObjChild) {
+    const char *jsonStr =
+        "{"
+        "\"test3\":\"testJsonToObjectWithObjChild\","
+        "\"test2\":{ \"name\":\"Test2 Object\", \"i\":-1234567 }"
+        "}";
+    
+    CxJsonValue *json;
+    cxJsonFromString(NULL, jsonStr, &json);
+    
+    CX_TEST_DO {
+        Test3 *obj = dbuJsonToObject(test3_class, NULL, json);
+        
+        CX_TEST_ASSERT(obj);
+        CX_TEST_ASSERT(!cx_strcmp(obj->test3, "testJsonToObjectWithObjChild"));
+        CX_TEST_ASSERT(obj->test2 != NULL);
+        CX_TEST_ASSERT(!cx_strcmp(obj->test2->name, "Test2 Object"));
+        CX_TEST_ASSERT(obj->test2->i == -1234567);
+        
+        free(obj);
+    }
+}
--- a/test/json.h	Sat Jan 03 18:19:58 2026 +0100
+++ b/test/json.h	Sun Jan 04 17:45:50 2026 +0100
@@ -45,6 +45,7 @@
 CX_TEST(testObjectToJsonChildList);
 
 CX_TEST(testJsonToSimpleObject);
+CX_TEST(testJsonToObjectWithObjChild);
 
 
 #ifdef __cplusplus
--- a/test/main.c	Sat Jan 03 18:19:58 2026 +0100
+++ b/test/main.c	Sun Jan 04 17:45:50 2026 +0100
@@ -145,6 +145,7 @@
     cx_test_register(suite, testObjectToJsonChildObj);
     cx_test_register(suite, testObjectToJsonChildList);
     cx_test_register(suite, testJsonToSimpleObject);
+    cx_test_register(suite, testJsonToObjectWithObjChild);
     
     cx_test_run_stdout(suite);
     

mercurial