This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/685-properties-json-serialization
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to 
refs/heads/feature/685-properties-json-serialization by this push:
     new 0e589441 gh-685: Fix several memleaks in properties encoding
0e589441 is described below

commit 0e5894419921ddbb5f4c4868cf6e7c99b463bfd2
Author: Pepijn Noltes <pnol...@apache.org>
AuthorDate: Sun Apr 14 23:03:53 2024 +0200

    gh-685: Fix several memleaks in properties encoding
---
 .../PropertiesEncodingErrorInjectionTestSuite.cc   |   8 +-
 .../utils/gtest/src/PropertiesEncodingTestSuite.cc | 107 ++++++++++++---------
 libs/utils/include/celix_properties.h              |  52 +++++++++-
 libs/utils/src/properties_encoding.c               |  23 +++--
 4 files changed, 126 insertions(+), 64 deletions(-)

diff --git a/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc 
b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc
index 3bcc804e..2553e0e9 100644
--- a/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc
+++ b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc
@@ -69,7 +69,7 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, 
SaveErrorTest) {
     celix_ei_expect_open_memstream((void*)celix_properties_saveToString, 0, 
nullptr);
 
     //When I call celix_properties_saveToString
-    char* out = nullptr;
+    char* out;
     status = celix_properties_saveToString(props, 0, &out);
 
     //Then I expect an error
@@ -90,7 +90,7 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, 
EncodeErrorTest) {
     
celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_saveToString,
 2, nullptr);
 
     // And I call celix_properties_saveToString using NESTED encoding 
(whitebox-knowledge)
-    char* out = nullptr;
+    char* out;
     auto status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_NESTED_STYLE, &out);
 
     // Then I expect an error
@@ -149,7 +149,7 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, 
EncodeArrayErrorTest) {
     celix_ei_expect_json_array((void*)celix_properties_saveToString, 4, 
nullptr);
 
     // And I call celix_properties_saveToString
-    char* out = nullptr;
+    char* out;
     auto status = celix_properties_saveToString(props, 0, &out);
 
     // Then I expect an error
@@ -189,7 +189,7 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, 
EncodeVersionErrorTest) {
     celix_ei_expect_json_sprintf((void*)celix_properties_saveToString, 4, 
nullptr);
 
     // And I call celix_properties_saveToString
-    char* out = nullptr;
+    char* out;
     auto status = celix_properties_saveToString(props, 0, &out);
 
     // Then I expect an error
diff --git a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc 
b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc
index d4ff8e17..0771aa3c 100644
--- a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc
+++ b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc
@@ -93,14 +93,17 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithNaNAndInfValuesTest)
         celix_autoptr(celix_properties_t) props = celix_properties_create();
         celix_properties_setDouble(props, key, strtod(key, nullptr));
 
-        //And an in-memory stream
-        celix_autofree char* buf = nullptr;
-        size_t bufLen = 0;
-        FILE* stream = open_memstream(&buf, &bufLen);
+        // Then saving the properties to a string succeeds, but value is not 
added to the JSON (because JSON does not
+        // support NAN, INF and -INF)
+        celix_autofree char* output;
+        auto status = celix_properties_saveToString(props, 0, &output);
+        ASSERT_EQ(CELIX_SUCCESS, status);
+        EXPECT_STREQ("{}", output);
 
-        //Then saving the properties to the stream fails, because JSON does 
not support NAN, INF and -INF
+        //And saving the properties to a string with the flag 
CELIX_PROPERTIES_ENCODE_ERROR_ON_NAN_INF fails
         celix_err_resetErrors();
-        auto status = celix_properties_saveToStream(props, stream, 0);
+        char* output2;
+        status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_ERROR_ON_NAN_INF, &output2);
         EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status);
 
         //And an error msg is added to celix_err
@@ -112,25 +115,30 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithNaNAndInfValuesTest)
 TEST_F(PropertiesSerializationTestSuite, SavePropertiesWithArrayListsTest) {
     // Given a properties object with array list values
     celix_autoptr(celix_properties_t) props = celix_properties_create();
+
     celix_array_list_t* list1 = celix_arrayList_createStringArray();
     celix_arrayList_addString(list1, "value1");
     celix_arrayList_addString(list1, "value2");
     celix_properties_assignArrayList(props, "key1", list1);
+
     celix_array_list_t* list2 = celix_arrayList_createLongArray();
     celix_arrayList_addLong(list2, 1);
     celix_arrayList_addLong(list2, 2);
     celix_properties_assignArrayList(props, "key2", list2);
+
     celix_array_list_t* list3 = celix_arrayList_createDoubleArray();
     celix_arrayList_addDouble(list3, 1.0);
     celix_arrayList_addDouble(list3, 2.0);
     celix_properties_assignArrayList(props, "key3", list3);
+
     celix_array_list_t* list4 = celix_arrayList_createBoolArray();
     celix_arrayList_addBool(list4, true);
     celix_arrayList_addBool(list4, false);
     celix_properties_assignArrayList(props, "key4", list4);
+
     celix_array_list_t* list5 = celix_arrayList_createVersionArray();
-    celix_arrayList_addVersion(list5, celix_version_create(1, 2, 3, 
"qualifier"));
-    celix_arrayList_addVersion(list5, celix_version_create(4, 5, 6, 
"qualifier"));
+    celix_arrayList_assignVersion(list5, celix_version_create(1, 2, 3, 
"qualifier"));
+    celix_arrayList_assignVersion(list5, celix_version_create(4, 5, 6, 
"qualifier"));
     celix_properties_assignArrayList(props, "key5", list5);
 
     // And an in-memory stream
@@ -170,17 +178,18 @@ TEST_F(PropertiesSerializationTestSuite, 
SaveEmptyArrayTest) {
     EXPECT_EQ(5, celix_properties_size(props));
 
     //When saving the properties to a string
-    char* output = nullptr;
-    auto status = celix_properties_saveToString(props, 0, &output);
+    celix_autofree char* output1;
+    auto status = celix_properties_saveToString(props, 0, &output1);
 
     //Then the save went ok
     ASSERT_EQ(CELIX_SUCCESS, status);
 
     //And the output contains an empty JSON object, because empty arrays are 
treated as unset
-    EXPECT_STREQ("{}", output);
+    EXPECT_STREQ("{}", output1);
 
     //When saving the properties to a string with an error on  empty array flag
-    status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_ERROR_ON_EMPTY_ARRAYS, &output);
+    char* output2;
+    status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_ERROR_ON_EMPTY_ARRAYS, &output2);
 
     //Then the save fails, because the empty array generates an error
     ASSERT_EQ(CELIX_ILLEGAL_ARGUMENT, status);
@@ -268,7 +277,7 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithKeyNamesWithSlashesTe
 
 
     //When saving the properties to a string
-    char* output = nullptr;
+    celix_autofree char* output;
     auto status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_NESTED_STYLE, &output);
     ASSERT_EQ(CELIX_SUCCESS, status);
 
@@ -329,18 +338,19 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithKeyCollision) {
     celix_properties_set(props, "key1/key2", "value2"); //collision with 
object "key1/key2" -> overwrite
 
     //When saving the properties to a string
-    char* output = nullptr;
-    auto status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_NESTED_STYLE, &output);
+    celix_autofree char* output1;
+    auto status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_NESTED_STYLE, &output1);
 
     //Then the save succeeds
     ASSERT_EQ(CELIX_SUCCESS, status);
 
     // And both keys are serialized (one as a flat key) (flat key name is 
whitebox knowledge)
-    EXPECT_NE(nullptr, strstr(output, R"({"key1":{"key2":"value2"}})")) << 
"JSON: " << output;
+    EXPECT_NE(nullptr, strstr(output1, R"({"key1":{"key2":"value2"}})")) << 
"JSON: " << output1;
 
     //When saving the properties to a string with the error on key collision 
flag
+    char* output2;
     status = celix_properties_saveToString(
-        props, CELIX_PROPERTIES_ENCODE_NESTED_STYLE | 
CELIX_PROPERTIES_ENCODE_ERROR_ON_COLLISIONS, &output);
+        props, CELIX_PROPERTIES_ENCODE_NESTED_STYLE | 
CELIX_PROPERTIES_ENCODE_ERROR_ON_COLLISIONS, &output2);
 
     //Then the save fails, because the keys collide
     ASSERT_EQ(CELIX_ILLEGAL_ARGUMENT, status);
@@ -357,7 +367,7 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithAndWithoutStrictFlagT
     celix_properties_assignArrayList(props, "key1", list);
 
     //When saving the properties to a string without the strict flag
-    char* output = nullptr;
+    celix_autofree char* output;
     auto status = celix_properties_saveToString(props, 0, &output);
 
     //Then the save succeeds
@@ -381,7 +391,7 @@ TEST_F(PropertiesSerializationTestSuite, 
SavePropertiesWithPrettyPrintTest) {
     celix_properties_set(props, "key2", "value2");
 
     //When saving the properties to a string with pretty print
-    char* output = nullptr;
+    celix_autofree char* output;
     auto status = celix_properties_saveToString(props, 
CELIX_PROPERTIES_ENCODE_PRETTY, &output);
 
     //Then the save succeeds
@@ -414,17 +424,14 @@ TEST_F(PropertiesSerializationTestSuite, 
SaveWithInvalidStreamTest) {
 TEST_F(PropertiesSerializationTestSuite, LoadEmptyPropertiesTest) {
     //Given an empty JSON object
     const char* json = "{}";
-    FILE* stream = fmemopen((void*)json, strlen(json), "r");
 
     //When loading the properties from the stream
     celix_autoptr(celix_properties_t) props = nullptr;
-    auto status = celix_properties_loadFromStream(stream, 0, &props);
+    auto status = celix_properties_loadFromString2(json, 0, &props);
     ASSERT_EQ(CELIX_SUCCESS, status);
 
     //Then the properties object is empty
     EXPECT_EQ(0, celix_properties_size(props));
-
-    fclose(stream);
 }
 
 TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithSingleValuesTest) {
@@ -586,7 +593,8 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadPropertiesWithEmptyArrayTest) {
     EXPECT_EQ(0, celix_properties_size(props));
 
     //When loading the properties from string with a strict flag
-    status = celix_properties_loadFromString2(inputJSON, 
CELIX_PROPERTIES_DECODE_ERROR_ON_EMPTY_ARRAYS, &props);
+    celix_properties_t* props2;
+    status = celix_properties_loadFromString2(inputJSON, 
CELIX_PROPERTIES_DECODE_ERROR_ON_EMPTY_ARRAYS, &props2);
 
     //Then loading fails, because the empty array generates an error
     ASSERT_EQ(CELIX_ILLEGAL_ARGUMENT, status);
@@ -651,7 +659,7 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadPropertiesWithDuplicatesTest) {
     EXPECT_EQ(3, celix_properties_getLong(props, "key", 0));
 
     // When decoding the properties from the stream using a flog that does not 
allow duplicates
-    celix_autoptr(celix_properties_t) props2 = nullptr;
+    celix_autoptr(celix_properties_t) props2;
     status = celix_properties_loadFromString2(jsonInput, 
CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2);
 
     // Then loading fails, because of a duplicate key
@@ -687,7 +695,7 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadPropertiesEscapedSlashesTest) {
     })";
 
     // When loading the properties from a string.
-    celix_autoptr(celix_properties_t) props = nullptr;
+    celix_autoptr(celix_properties_t) props;
     auto status = celix_properties_loadFromString2(jsonInput, 0, &props);
 
     // Then loading succeeds
@@ -703,7 +711,7 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadPropertiesEscapedSlashesTest) {
     EXPECT_STREQ("value7", celix_properties_getString(props, "object3/key4"));
 
     // When decoding the properties from a string using a flag that allows 
duplicates
-    celix_autoptr(celix_properties_t) props2 = nullptr;
+    celix_autoptr(celix_properties_t) props2;
     status = celix_properties_loadFromString2(jsonInput, 
CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2);
 
     // Then loading fails, because of a duplicate key
@@ -714,7 +722,7 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadPropertiesEscapedSlashesTest) {
     celix_err_printErrors(stderr, "Test Error: ", "\n");
 
     // When decoding the properties from a string using a flag that allows 
collisions
-    celix_autoptr(celix_properties_t) props3 = nullptr;
+    celix_autoptr(celix_properties_t) props3;
     status = celix_properties_loadFromString2(jsonInput, 
CELIX_PROPERTIES_DECODE_ERROR_ON_COLLISIONS, &props3);
 
     // Then loading fails, because of a collision
@@ -861,34 +869,41 @@ TEST_F(PropertiesSerializationTestSuite, 
LoadWithInvalidStreamTest) {
 TEST_F(PropertiesSerializationTestSuite, SaveAndLoadFlatProperties) {
     // Given a properties object with all possible types (but no empty arrays)
     celix_autoptr(celix_properties_t) props = celix_properties_create();
-    celix_properties_set(props, "strKey", "strValue");
-    celix_properties_setLong(props, "longKey", 42);
-    celix_properties_setDouble(props, "doubleKey", 2.0);
-    celix_properties_setBool(props, "boolKey", true);
-    celix_properties_setVersion(props, "versionKey", celix_version_create(1, 
2, 3, "qualifier"));
-    auto* strArr = celix_arrayList_createStringArray();
+
+    celix_properties_set(props, "single/strKey", "strValue");
+    celix_properties_setLong(props, "single/longKey", 42);
+    celix_properties_setDouble(props, "single/doubleKey", 2.0);
+    celix_properties_setBool(props, "single/boolKey", true);
+    celix_properties_assignVersion(props, "single/versionKey", 
celix_version_create(1, 2, 3, "qualifier"));
+
+    celix_array_list_t* strArr = celix_arrayList_createStringArray();
     celix_arrayList_addString(strArr, "value1");
     celix_arrayList_addString(strArr, "value2");
-    auto* longArr = celix_arrayList_createLongArray();
+    celix_properties_assignArrayList(props, "array/stringArr", strArr);
+
+    celix_array_list_t* longArr = celix_arrayList_createLongArray();
     celix_arrayList_addLong(longArr, 1);
     celix_arrayList_addLong(longArr, 2);
-    celix_properties_assignArrayList(props, "longArr", longArr);
-    auto* doubleArr = celix_arrayList_createDoubleArray();
+    celix_properties_assignArrayList(props, "array/longArr", longArr);
+
+    celix_array_list_t* doubleArr = celix_arrayList_createDoubleArray();
     celix_arrayList_addDouble(doubleArr, 1.0);
     celix_arrayList_addDouble(doubleArr, 2.0);
-    celix_properties_assignArrayList(props, "doubleArr", doubleArr);
-    auto* boolArr = celix_arrayList_createBoolArray();
+    celix_properties_assignArrayList(props, "array/doubleArr", doubleArr);
+
+    celix_array_list_t* boolArr = celix_arrayList_createBoolArray();
     celix_arrayList_addBool(boolArr, true);
     celix_arrayList_addBool(boolArr, false);
-    celix_properties_assignArrayList(props, "boolArr", boolArr);
-    auto* versionArr = celix_arrayList_createVersionArray();
-    celix_arrayList_addVersion(versionArr, celix_version_create(1, 2, 3, 
"qualifier"));
-    celix_arrayList_addVersion(versionArr, celix_version_create(4, 5, 6, 
"qualifier"));
-    celix_properties_assignArrayList(props, "versionArr", versionArr);
+    celix_properties_assignArrayList(props, "array/boolArr", boolArr);
+
+    celix_array_list_t* versionArr = celix_arrayList_createVersionArray();
+    celix_arrayList_assignVersion(versionArr, celix_version_create(1, 2, 3, 
"qualifier"));
+    celix_arrayList_assignVersion(versionArr, celix_version_create(4, 5, 6, 
"qualifier"));
+    celix_properties_assignArrayList(props, "array/versionArr", versionArr);
 
     // When saving the properties to a properties_test.json file
     const char* filename = "properties_test.json";
-    auto status = celix_properties_save(props, filename, 0);
+    auto status = celix_properties_save(props, filename, 
CELIX_PROPERTIES_ENCODE_PRETTY);
 
     // Then saving succeeds
     ASSERT_EQ(CELIX_SUCCESS, status);
@@ -902,4 +917,4 @@ TEST_F(PropertiesSerializationTestSuite, 
SaveAndLoadFlatProperties) {
 
     // And the loaded properties are equal to the original properties
     EXPECT_TRUE(celix_properties_equals(props, loadedProps));
-}
+}
\ No newline at end of file
diff --git a/libs/utils/include/celix_properties.h 
b/libs/utils/include/celix_properties.h
index a483f26a..2ac692ea 100644
--- a/libs/utils/include/celix_properties.h
+++ b/libs/utils/include/celix_properties.h
@@ -1020,6 +1020,16 @@ CELIX_UTILS_EXPORT bool 
celix_propertiesIterator_equals(const celix_properties_i
  */
 #define CELIX_PROPERTIES_ENCODE_ERROR_ON_EMPTY_ARRAYS 0x20
 
+/**
+ * @brief Flag to indicate that the encoding should fail if the JSON 
representation will contain NaN or Inf values.
+ *
+ * NaN, Inf and -Inf are not valid JSON values and as such properties entries 
with these values are not encoded.
+ *
+ * If this flag is set, the encoding will fail if the JSON representation will 
contain NaN or Inf values and if this
+ * flag is not set, the encoding will not fail and the NaN and Inf entries 
will be ignored.
+ */
+#define CELIX_PROPERTIES_ENCODE_ERROR_ON_NAN_INF 0x40
+
 /**
  * @brief Flag to indicate that all encode "error on" flags should be set.
  */
@@ -1031,7 +1041,26 @@ CELIX_UTILS_EXPORT bool 
celix_propertiesIterator_equals(const celix_properties_i
  *
  * The stream is expected to be a valid stream and is not reset or closed by 
this function.
  *
- * TODO document the JSON format
+ * Properties are encoded as a JSON object.
+ *
+ * If no encoding style flag is set of when the 
CELIX_PROPERTIES_ENCODE_FLAT_STYLE flag is set, properties
+ * entries are written as top level field entries.
+ *
+ * If the CELIX_PROPERTIES_ENCODE_NESTED_STYLE flag is set, properties entry 
keys are split on '/' and nested in
+ * JSON objects. This leads to a more natural JSON representation, but if 
there are colliding properties keys (e.g.
+ * `{"key": "value1", "key/with/slash": "value2"}`), not all properties 
entries will be written.
+ *
+ * With all encoding styles, the empty array properties entries are ignored, 
because they cannot be decoded to a valid
+ * properties array entry.
+ *
+ * Properties type entries are encoded as follows:
+ * - CELIX_PROPERTIES_TYPE_STRING: The value is encoded as a JSON string.
+ * - CELIX_PROPERTIES_TYPE_LONG: The value is encoded as a JSON number.
+ * - CELIX_PROPERTIES_TYPE_DOUBLE: The value is encoded as a JSON number.
+ * - CELIX_PROPERTIES_TYPE_BOOL: The value is encoded as a JSON boolean.
+ * - CELIX_PROPERTIES_TYPE_ARRAY: The value is encoded as a JSON array, with 
each element encoded according to its type.
+ * - CELIX_PROPERTIES_TYPE_VERSION: The value is encoded as a JSON string with 
a "version<" prefix and a ">" suffix
+ * (e.g. "version<1.2.3>").
  *
  * For a overview of the possible encode flags, see the 
CELIX_PROPERTIES_ENCODE_* flags documentation.
  * The default encoding style is a compact and flat JSON representation.
@@ -1168,7 +1197,26 @@ CELIX_UTILS_EXPORT celix_status_t 
celix_properties_saveToString(const celix_prop
  * The stream is expected to be a valid readable stream and is not reset or 
closed by this function.
  * The content of the stream is expected to be in the format of a JSON object.
  *
- * TODO describe allowed and disallowed JSON objects.
+ * For decoding a single JSON object is decoded to a properties object.
+ *
+ * The keys of the JSON object are used as
+ * properties keys and the values of the JSON object are used as properties 
values. If there are nested
+ * JSON objects, the keys are concatenated with a '/' separator (e.g. `{"key": 
{"nested": "value"}}` will be
+ * decoded to a properties object with a single entry with key `key/nested` 
and (string) value `value`).
+ *
+ * Because properties keys are created by concatenating the JSON keys, there 
there could be collisions
+ * (e.g. `{"obj/key": "value", "obj": {"key": "value2"}}`, two entries with 
the key `obj/key`. In this case
+ * the last decoded JSON entry will be used.
+ *
+ * Properties entry types are determined by the JSON value type:
+ * - JSON string values are decoded as string properties entries.
+ * - JSON number values are decoded as long or double properties entries, 
depending on the value.
+ * - JSON boolean values are decoded as boolean properties entries.
+ * - jSON string values with a "version<" prefix and a ">" suffix are decoded 
as version properties entries (e.g.
+ * "version<1.2.3>").
+ * - JSON array values are decoded as array properties entries. The array can 
contain any of the above types, but mixed
+ * arrays are not supported.
+ * - JSON null values are ignored.
  *
  * For a overview of the possible decode flags, see the 
CELIX_PROPERTIES_DECODE_* flags documentation.
  *
diff --git a/libs/utils/src/properties_encoding.c 
b/libs/utils/src/properties_encoding.c
index 2b5c693b..eba39207 100644
--- a/libs/utils/src/properties_encoding.c
+++ b/libs/utils/src/properties_encoding.c
@@ -130,8 +130,11 @@ celix_properties_entryValueToJson(const char* key, const 
celix_properties_entry_
         break;
     case CELIX_PROPERTIES_VALUE_TYPE_DOUBLE:
         if (isnan(entry->typed.doubleValue) || 
isinf(entry->typed.doubleValue)) {
-            celix_err_pushf("Invalid NaN or Inf in key '%s'.", key);
-            return CELIX_ILLEGAL_ARGUMENT;
+            if (flags & CELIX_PROPERTIES_ENCODE_ERROR_ON_NAN_INF) {
+                celix_err_pushf("Invalid NaN or Inf in key '%s'.", key);
+                return CELIX_ILLEGAL_ARGUMENT;
+            }
+            return CELIX_SUCCESS; // ignore NaN and Inf
         }
         *out = json_real(entry->typed.doubleValue);
         break;
@@ -184,10 +187,8 @@ static celix_status_t 
celix_properties_addPropertiesEntryFlatToJson(const celix_
                                                                     int flags) 
{
     json_t* value;
     celix_status_t status = celix_properties_entryValueToJson(key, entry, 
flags, &value);
-    if (status != CELIX_SUCCESS) {
-        return status;
-    }
-    return celix_properties_addJsonValueToJson(value, key, root, flags);
+    status = CELIX_DO_IF(status, celix_properties_addJsonValueToJson(value, 
key, root, flags));
+    return status;
 }
 
 static celix_status_t celix_properties_addPropertiesEntryToJson(const 
celix_properties_entry_t* entry,
@@ -237,7 +238,7 @@ static celix_status_t 
celix_properties_addPropertiesEntryToJson(const celix_prop
 }
 
 celix_status_t celix_properties_saveToStream(const celix_properties_t* 
properties, FILE* stream, int encodeFlags) {
-    json_t* root = json_object();
+    json_auto_t* root = json_object();
     if (!root) {
         celix_err_push("Failed to create json object");
         return ENOMEM;
@@ -257,7 +258,6 @@ celix_status_t celix_properties_saveToStream(const 
celix_properties_t* propertie
             status = celix_properties_addPropertiesEntryToJson(&iter.entry, 
iter.key, root, encodeFlags);
         }
         if (status != CELIX_SUCCESS) {
-            json_decref(root);
             return status;
         }
     }
@@ -268,7 +268,6 @@ celix_status_t celix_properties_saveToStream(const 
celix_properties_t* propertie
     }
 
     int rc = json_dumpf(root, stream, jsonFlags);
-    json_decref(root);
     if (rc != 0) {
         celix_err_push("Failed to dump json object to stream.");
         return CELIX_FILE_IO_EXCEPTION;
@@ -432,7 +431,7 @@ celix_properties_decodeArray(celix_properties_t* props, 
const char* key, const j
         case CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION: {
             celix_version_t* v;
             status = celix_properties_parseVersion(json_string_value(value), 
&v);
-            status = CELIX_DO_IF(status, celix_arrayList_addVersion(array, v));
+            status = CELIX_DO_IF(status, celix_arrayList_assignVersion(array, 
v));
             break;
         }
         default:
@@ -468,7 +467,7 @@ celix_properties_decodeValue(celix_properties_t* props, 
const char* key, json_t*
     if (json_is_string(jsonValue) && 
celix_properties_isVersionString(json_string_value(jsonValue))) {
         celix_version_t* version;
         status = celix_properties_parseVersion(json_string_value(jsonValue), 
&version);
-        status = CELIX_DO_IF(status, celix_properties_setVersion(props, key, 
version));
+        status = CELIX_DO_IF(status, celix_properties_assignVersion(props, 
key, version));
     } else if (json_is_string(jsonValue)) {
         status = celix_properties_setString(props, key, 
json_string_value(jsonValue));
     } else if (json_is_integer(jsonValue)) {
@@ -549,7 +548,7 @@ celix_status_t celix_properties_loadFromStream(FILE* 
stream, int decodeFlags, ce
     if (decodeFlags & CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES) {
         jsonFlags = JSON_REJECT_DUPLICATES;
     }
-    json_t* root = json_loadf(stream, jsonFlags, &jsonError);
+    json_auto_t* root = json_loadf(stream, jsonFlags, &jsonError);
     if (!root) {
         celix_err_pushf("Failed to parse json: %s.", jsonError.text);
         return CELIX_ILLEGAL_ARGUMENT;

Reply via email to