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

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

commit a8038ecf565df5afb952e1e3b0cd0dadb9e13e89
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun Jan 7 17:25:55 2024 +0100

    Add str, long, double, bool and version array support to properties
---
 libs/utils/gtest/src/PropertiesTestSuite.cc | 346 +++++++++++++++++--
 libs/utils/include/celix_properties.h       | 436 +++++++++++++++++++++++-
 libs/utils/src/properties.c                 | 495 ++++++++++++++++++++++++++--
 3 files changed, 1229 insertions(+), 48 deletions(-)

diff --git a/libs/utils/gtest/src/PropertiesTestSuite.cc 
b/libs/utils/gtest/src/PropertiesTestSuite.cc
index 8e969666..999b9a28 100644
--- a/libs/utils/gtest/src/PropertiesTestSuite.cc
+++ b/libs/utils/gtest/src/PropertiesTestSuite.cc
@@ -29,25 +29,28 @@
 using ::testing::MatchesRegex;
 
 class PropertiesTestSuite : public ::testing::Test {
-public:
-  PropertiesTestSuite() {
-      celix_err_resetErrors();
-  }
-
-  void printStats(const celix_properties_statistics_t* stats) {
-      printf("Properties statistics:\n");
-      printf("|- nr of entries: %zu\n", stats->mapStatistics.nrOfEntries);
-      printf("|- nr of buckets: %zu\n", stats->mapStatistics.nrOfBuckets);
-      printf("|- average nr of entries in bucket: %f\n", 
stats->mapStatistics.averageNrOfEntriesPerBucket);
-      printf("|- stddev nr of entries in bucket: %f\n", 
stats->mapStatistics.stdDeviationNrOfEntriesPerBucket);
-      printf("|- resize count: %zu\n", stats->mapStatistics.resizeCount);
-      printf("|- size of keys and string values: %zu bytes\n", 
stats->sizeOfKeysAndStringValues);
-      printf("|- average size of keys and string values: %f bytes\n", 
stats->averageSizeOfKeysAndStringValues);
-      printf("|- fill string optimization buffer percentage: %f\n", 
stats->fillStringOptimizationBufferPercentage);
-      printf("|- fill entries optimization buffer percentage: %f\n", 
stats->fillEntriesOptimizationBufferPercentage);
-  }
-};
+  public:
+    PropertiesTestSuite() { celix_err_resetErrors(); }
+
+    void printStats(const celix_properties_statistics_t* stats) {
+        printf("Properties statistics:\n");
+        printf("|- nr of entries: %zu\n", stats->mapStatistics.nrOfEntries);
+        printf("|- nr of buckets: %zu\n", stats->mapStatistics.nrOfBuckets);
+        printf("|- average nr of entries in bucket: %f\n", 
stats->mapStatistics.averageNrOfEntriesPerBucket);
+        printf("|- stddev nr of entries in bucket: %f\n", 
stats->mapStatistics.stdDeviationNrOfEntriesPerBucket);
+        printf("|- resize count: %zu\n", stats->mapStatistics.resizeCount);
+        printf("|- size of keys and string values: %zu bytes\n", 
stats->sizeOfKeysAndStringValues);
+        printf("|- average size of keys and string values: %f bytes\n", 
stats->averageSizeOfKeysAndStringValues);
+        printf("|- fill string optimization buffer percentage: %f\n", 
stats->fillStringOptimizationBufferPercentage);
+        printf("|- fill entries optimization buffer percentage: %f\n", 
stats->fillEntriesOptimizationBufferPercentage);
+    }
 
+    void checkVersions(const celix_version_t* version1, const celix_version_t* 
version2) {
+        EXPECT_EQ(0, celix_version_compareTo(version1, version2))
+            << "Expected version " << celix_version_toString(version1) << " to 
be equal to "
+            << celix_version_toString(version2);
+    }
+};
 
 TEST_F(PropertiesTestSuite, CreateTest) {
     auto* properties = celix_properties_create();
@@ -724,7 +727,42 @@ TEST_F(PropertiesTestSuite, 
SetDoubleWithLargeStringRepresentationTest) {
     ASSERT_EQ(CELIX_SUCCESS, celix_properties_setDouble(props, 
"large_str_value", 12345678901234567890.1234567890));
 }
 
-TEST_F(PropertiesTestSuite, LongArrayTestSuite) {
+TEST_F(PropertiesTestSuite, GetLongDoubleBoolVersionAndStringTest) {
+
+    celix_autoptr(celix_properties_t) props = celix_properties_create();
+    celix_properties_setLong(props, "long", 42);
+    celix_properties_setDouble(props, "double", 3.14);
+    celix_properties_setBool(props, "bool", true);
+    celix_properties_set(props, "str", "value");
+    celix_version_t* version = celix_version_create(1, 2, 3, nullptr);
+    celix_properties_assignVersion(props, "version", version);
+
+    // check if the values are correctly returned
+    EXPECT_STREQ("value", celix_properties_get(props, "str", nullptr));
+    EXPECT_EQ(42, celix_properties_getLong(props, "long", -1L));
+    EXPECT_DOUBLE_EQ(3.14, celix_properties_getDouble(props, "double", -1.0));
+    EXPECT_EQ(true, celix_properties_getBool(props, "bool", false));
+    EXPECT_EQ(version, celix_properties_getVersion(props, "version", nullptr));
+
+    // check if the values are correctly returned if value is not found
+    EXPECT_EQ(nullptr, celix_properties_get(props, "non-existing", nullptr));
+    EXPECT_EQ(-1L, celix_properties_getLong(props, "non-existing", -1L));
+    EXPECT_DOUBLE_EQ(-1.0, celix_properties_getDouble(props, "non-existing", 
-1.0));
+    EXPECT_EQ(false, celix_properties_getBool(props, "non-existing", false));
+    EXPECT_EQ(nullptr, celix_properties_getVersion(props, "non-existing", 
nullptr));
+
+    // check if the values are correctly returned if the found value is not of 
the correct type
+    EXPECT_EQ(-1L, celix_properties_getLong(props, "str", -1L));
+    EXPECT_DOUBLE_EQ(-1.0, celix_properties_getDouble(props, "str", -1.0));
+    EXPECT_EQ(false, celix_properties_getBool(props, "str", false));
+    EXPECT_EQ(nullptr, celix_properties_getVersion(props, "str", nullptr));
+
+    // check if a default ptr is correctly returned if value is not found for 
string and version
+    EXPECT_EQ("default", celix_properties_get(props, "non-existing", 
"default"));
+    EXPECT_EQ(version, celix_properties_getVersion(props, "non-existing", 
version));
+}
+
+TEST_F(PropertiesTestSuite, LongArrayListTest) {
     celix_autoptr(celix_properties_t) props = celix_properties_create();
 
     long array1[] = {1, 2, 3, 4, 5};
@@ -767,8 +805,278 @@ TEST_F(PropertiesTestSuite, LongArrayTestSuite) {
     EXPECT_EQ(4, celix_arrayList_getLong(retrievedList3, 0));
     EXPECT_EQ(5, celix_arrayList_getLong(retrievedList3, 1));
 
+    celix_array_list* retrievedList4;
+    celix_autoptr(celix_array_list_t) defaultList = celix_arrayList_create();
+    celix_arrayList_addLong(defaultList, 6);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_getAsLongArrayList(props, 
"non-existing", defaultList, &retrievedList4));
+    ASSERT_NE(nullptr, retrievedList4);
+    ASSERT_EQ(1, celix_arrayList_size(retrievedList4));
+    EXPECT_EQ(6, celix_arrayList_getLong(retrievedList4, 0));
+    celix_arrayList_destroy(retrievedList4);
+
     auto* getList = celix_properties_getLongArrayList(props, "array2", 
nullptr);
     EXPECT_NE(array2, getList);
     getList = celix_properties_getLongArrayList(props, "array3", nullptr);
     EXPECT_EQ(array3, getList);
 }
+
+TEST_F(PropertiesTestSuite, DoubleArrayListTest) {
+    celix_autoptr(celix_properties_t) props = celix_properties_create();
+
+    double array1[] = {1.1, 2.2, 3.3, 4.4, 5.5};
+    ASSERT_EQ(CELIX_SUCCESS, celix_properties_setDoubles(props, "array1", 
array1, 5));
+    EXPECT_EQ(1, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList1;
+    celix_status_t status = celix_properties_getAsDoubleArrayList(props, 
"array1", nullptr, &retrievedList1);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList1 != nullptr);
+    EXPECT_EQ(5, celix_arrayList_size(retrievedList1));
+    EXPECT_EQ(1.1, celix_arrayList_getDouble(retrievedList1, 0));
+    EXPECT_EQ(5.5, celix_arrayList_getDouble(retrievedList1, 4));
+
+    celix_autoptr(celix_array_list_t) array2 = celix_arrayList_create();
+    celix_arrayList_addDouble(array2, 1.1);
+    celix_arrayList_addDouble(array2, 2.2);
+    celix_arrayList_addDouble(array2, 3.3);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_setDoubleArrayList(props, 
"array2", array2));
+    EXPECT_EQ(2, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList2;
+    status = celix_properties_getAsDoubleArrayList(props, "array2", nullptr, 
&retrievedList2);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList2 != nullptr);
+    EXPECT_NE(array2, retrievedList2);
+    EXPECT_EQ(3, celix_arrayList_size(retrievedList2));
+    EXPECT_EQ(1.1, celix_arrayList_getDouble(retrievedList2, 0));
+    EXPECT_EQ(3.3, celix_arrayList_getDouble(retrievedList2, 2));
+
+    celix_array_list_t* array3 = celix_arrayList_create();
+    celix_arrayList_addDouble(array3, 4.4);
+    celix_arrayList_addDouble(array3, 5.5);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_assignDoubleArrayList(props, 
"array3", array3));
+    EXPECT_EQ(3, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList3;
+    status = celix_properties_getAsDoubleArrayList(props, "array3", nullptr, 
&retrievedList3);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList3 != nullptr);
+    EXPECT_NE(array3, retrievedList3);
+    EXPECT_EQ(2, celix_arrayList_size(retrievedList3));
+    EXPECT_EQ(4.4, celix_arrayList_getDouble(retrievedList3, 0));
+    EXPECT_EQ(5.5, celix_arrayList_getDouble(retrievedList3, 1));
+
+    celix_array_list* retrievedList4;
+    celix_autoptr(celix_array_list_t) defaultList = celix_arrayList_create();
+    celix_arrayList_addDouble(defaultList, 6.6);
+    EXPECT_EQ(CELIX_SUCCESS,
+              celix_properties_getAsDoubleArrayList(props, "non-existing", 
defaultList, &retrievedList4));
+    ASSERT_NE(nullptr, retrievedList4);
+    ASSERT_EQ(1, celix_arrayList_size(retrievedList4));
+    EXPECT_EQ(6.6, celix_arrayList_getDouble(retrievedList4, 0));
+    celix_arrayList_destroy(retrievedList4);
+
+    auto* getList = celix_properties_getDoubleArrayList(props, "array2", 
nullptr);
+    EXPECT_NE(array2, getList);
+    getList = celix_properties_getDoubleArrayList(props, "array3", nullptr);
+    EXPECT_EQ(array3, getList);
+}
+
+TEST_F(PropertiesTestSuite, BoolArrayListTest) {
+    celix_autoptr(celix_properties_t) props = celix_properties_create();
+
+    bool array1[] = {true, false, true, false, true};
+    ASSERT_EQ(CELIX_SUCCESS, celix_properties_setBooleans(props, "array1", 
array1, 5));
+    EXPECT_EQ(1, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList1;
+    celix_status_t status = celix_properties_getAsBoolArrayList(props, 
"array1", nullptr, &retrievedList1);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList1 != nullptr);
+    EXPECT_EQ(5, celix_arrayList_size(retrievedList1));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList1, 0));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList1, 2));
+    EXPECT_EQ(false, celix_arrayList_getBool(retrievedList1, 1));
+    EXPECT_EQ(false, celix_arrayList_getBool(retrievedList1, 3));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList1, 4));
+
+    celix_autoptr(celix_array_list_t) array2 = celix_arrayList_create();
+    celix_arrayList_addBool(array2, true);
+    celix_arrayList_addBool(array2, false);
+    celix_arrayList_addBool(array2, true);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_setBoolArrayList(props, 
"array2", array2));
+    EXPECT_EQ(2, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList2;
+    status = celix_properties_getAsBoolArrayList(props, "array2", nullptr, 
&retrievedList2);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList2 != nullptr);
+    EXPECT_NE(array2, retrievedList2);
+    EXPECT_EQ(3, celix_arrayList_size(retrievedList2));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList2, 0));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList2, 2));
+    EXPECT_EQ(false, celix_arrayList_getBool(retrievedList2, 1));
+
+    celix_array_list_t* array3 = celix_arrayList_create();
+    celix_arrayList_addBool(array3, false);
+    celix_arrayList_addBool(array3, true);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_assignBoolArrayList(props, 
"array3", array3));
+    EXPECT_EQ(3, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList3;
+    status = celix_properties_getAsBoolArrayList(props, "array3", nullptr, 
&retrievedList3);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList3 != nullptr);
+    EXPECT_NE(array3, retrievedList3);
+    EXPECT_EQ(2, celix_arrayList_size(retrievedList3));
+    EXPECT_EQ(false, celix_arrayList_getBool(retrievedList3, 0));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList3, 1));
+
+    celix_array_list* retrievedList4;
+    celix_autoptr(celix_array_list_t) defaultList = celix_arrayList_create();
+    celix_arrayList_addBool(defaultList, true);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_getAsBoolArrayList(props, 
"non-existing", defaultList, &retrievedList4));
+    ASSERT_NE(nullptr, retrievedList4);
+    ASSERT_EQ(1, celix_arrayList_size(retrievedList4));
+    EXPECT_EQ(true, celix_arrayList_getBool(retrievedList4, 0));
+    celix_arrayList_destroy(retrievedList4);
+
+    auto* getList = celix_properties_getBoolArrayList(props, "array2", 
nullptr);
+    EXPECT_NE(array2, getList);
+    getList = celix_properties_getBoolArrayList(props, "array3", nullptr);
+    EXPECT_EQ(array3, getList);
+}
+
+TEST_F(PropertiesTestSuite, StringArrayListTest) {
+    celix_autoptr(celix_properties_t) props = celix_properties_create();
+
+    const char* str1 = "string1";
+    const char* str2 = "string2";
+    const char* str3 = "string3";
+    const char* str4 = "string4";
+    const char* str5 = "string5";
+
+    const char* array1[] = {str1, str2, str3, str4, str5};
+    ASSERT_EQ(CELIX_SUCCESS, celix_properties_setStrings(props, "array1", 
array1, 5));
+    EXPECT_EQ(1, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList1;
+    celix_status_t status = celix_properties_getAsStringArrayList(props, 
"array1", nullptr, &retrievedList1);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList1 != nullptr);
+    EXPECT_EQ(5, celix_arrayList_size(retrievedList1));
+    EXPECT_STREQ(str1, (const char*)celix_arrayList_get(retrievedList1, 0));
+    EXPECT_STREQ(str2, (const char*)celix_arrayList_get(retrievedList1, 1));
+    EXPECT_STREQ(str3, (const char*)celix_arrayList_get(retrievedList1, 2));
+    EXPECT_STREQ(str4, (const char*)celix_arrayList_get(retrievedList1, 3));
+    EXPECT_STREQ(str5, (const char*)celix_arrayList_get(retrievedList1, 4));
+
+    celix_autoptr(celix_array_list_t) array2 = celix_arrayList_create();
+    celix_arrayList_addString(array2, str1);
+    celix_arrayList_addString(array2, str1);
+    celix_arrayList_addString(array2, str1);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_setStringArrayList(props, 
"array2", array2));
+    EXPECT_EQ(2, celix_properties_size(props));
+
+    celix_autoptr(celix_array_list_t) retrievedList2;
+    status = celix_properties_getAsStringArrayList(props, "array2", nullptr, 
&retrievedList2);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList2 != nullptr);
+    EXPECT_NE(array2, retrievedList2);
+    EXPECT_EQ(3, celix_arrayList_size(retrievedList2));
+    EXPECT_STREQ(str1, (const char*)celix_arrayList_get(retrievedList2, 0));
+    EXPECT_STREQ(str1, (const char*)celix_arrayList_get(retrievedList2, 1));
+    EXPECT_STREQ(str1, (const char*)celix_arrayList_get(retrievedList2, 2));
+
+    celix_array_list_t* array3 = celix_arrayList_create();
+    celix_arrayList_addString(array3, str4);
+    celix_arrayList_addString(array3, str5);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_assignStringArrayList(props, 
"array3", array3));
+    EXPECT_EQ(3, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList3;
+    status = celix_properties_getAsStringArrayList(props, "array3", nullptr, 
&retrievedList3);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList3 != nullptr);
+    EXPECT_NE(array3, retrievedList3);
+    EXPECT_EQ(2, celix_arrayList_size(retrievedList3));
+    EXPECT_STREQ(str4, (const char*)celix_arrayList_get(retrievedList3, 0));
+    EXPECT_STREQ(str5, (const char*)celix_arrayList_get(retrievedList3, 1));
+
+    celix_array_list* retrievedList4;
+    celix_autoptr(celix_array_list_t) defaultList = celix_arrayList_create();
+    celix_arrayList_addString(defaultList, str1);
+    EXPECT_EQ(CELIX_SUCCESS,
+              celix_properties_getAsStringArrayList(props, "non-existing", 
defaultList, &retrievedList4));
+    ASSERT_NE(nullptr, retrievedList4);
+    ASSERT_EQ(1, celix_arrayList_size(retrievedList4));
+    EXPECT_STREQ(str1, (const char*)celix_arrayList_get(retrievedList4, 0));
+    celix_arrayList_destroy(retrievedList4);
+
+    auto* getList = celix_properties_getStringArrayList(props, "array2", 
nullptr);
+    EXPECT_NE(array2, getList);
+    getList = celix_properties_getStringArrayList(props, "array3", nullptr);
+    EXPECT_EQ(array3, getList);
+}
+
+TEST_F(PropertiesTestSuite, VersionArrayListTest) {
+    celix_autoptr(celix_properties_t) props = celix_properties_create();
+
+    celix_autoptr(celix_version_t) v1 = celix_version_create(1, 2, 3, nullptr);
+    celix_autoptr(celix_version_t) v2 = celix_version_create(4, 5, 6, nullptr);
+    celix_autoptr(celix_version_t) v3 = celix_version_create(7, 8, 9, nullptr);
+    celix_autoptr(celix_version_t) v4 = celix_version_create(10, 11, 12, 
nullptr);
+    celix_autoptr(celix_version_t) v5 = celix_version_create(13, 14, 15, 
nullptr);
+
+    const celix_version_t* array1[] = {v1, v2, v3, v4, v5};
+    ASSERT_EQ(CELIX_SUCCESS, celix_properties_setVersions(props, "array1", 
array1, 5));
+    EXPECT_EQ(1, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList1;
+    celix_status_t status = celix_properties_getAsVersionArrayList(props, 
"array1", nullptr, &retrievedList1);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList1 != nullptr);
+    EXPECT_EQ(5, celix_arrayList_size(retrievedList1));
+    checkVersions(v1, (celix_version_t*)celix_arrayList_get(retrievedList1, 
0));
+    checkVersions(v2, (celix_version_t*)celix_arrayList_get(retrievedList1, 
1));
+    checkVersions(v3, (celix_version_t*)celix_arrayList_get(retrievedList1, 
2));
+    checkVersions(v4, (celix_version_t*)celix_arrayList_get(retrievedList1, 
3));
+    checkVersions(v5, (celix_version_t*)celix_arrayList_get(retrievedList1, 
4));
+
+    celix_autoptr(celix_array_list_t) array2 = celix_arrayList_create();
+    celix_arrayList_add(array2, v1);
+    celix_arrayList_add(array2, v2);
+    celix_arrayList_add(array2, v3);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_setVersionArrayList(props, 
"array2", array2));
+    EXPECT_EQ(2, celix_properties_size(props));
+
+    celix_autoptr(celix_array_list_t) retrievedList2;
+    status = celix_properties_getAsVersionArrayList(props, "array2", nullptr, 
&retrievedList2);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList2 != nullptr);
+    EXPECT_NE(array2, retrievedList2);
+    EXPECT_EQ(3, celix_arrayList_size(retrievedList2));
+    checkVersions(v1, (celix_version_t*)celix_arrayList_get(retrievedList2, 
0));
+    checkVersions(v2, (celix_version_t*)celix_arrayList_get(retrievedList2, 
1));
+    checkVersions(v3, (celix_version_t*)celix_arrayList_get(retrievedList2, 
2));
+
+    celix_array_list_t* array3 = celix_arrayList_create();
+    celix_arrayList_add(array3, v4);
+    celix_arrayList_add(array3, v5);
+    EXPECT_EQ(CELIX_SUCCESS, celix_properties_assignVersionArrayList(props, 
"array3", array3));
+    EXPECT_EQ(3, celix_properties_size(props));
+    celix_autoptr(celix_array_list_t) retrievedList3;
+    status = celix_properties_getAsVersionArrayList(props, "array3", nullptr, 
&retrievedList3);
+    ASSERT_EQ(CELIX_SUCCESS, status);
+    ASSERT_TRUE(retrievedList3 != nullptr);
+    EXPECT_NE(array3, retrievedList3);
+    EXPECT_EQ(2, celix_arrayList_size(retrievedList3));
+    checkVersions(v4, (celix_version_t*)celix_arrayList_get(retrievedList3, 
0));
+    checkVersions(v5, (celix_version_t*)celix_arrayList_get(retrievedList3, 
1));
+
+    celix_array_list* retrievedList4;
+    celix_autoptr(celix_array_list_t) defaultList = celix_arrayList_create();
+    celix_arrayList_add(defaultList, v1);
+    EXPECT_EQ(CELIX_SUCCESS,
+              celix_properties_getAsVersionArrayList(props, "non-existing", 
defaultList, &retrievedList4));
+    ASSERT_NE(nullptr, retrievedList4);
+    ASSERT_EQ(1, celix_arrayList_size(retrievedList4));
+    checkVersions(v1, (celix_version_t*)celix_arrayList_get(retrievedList4, 
0));
+    celix_arrayList_destroy(retrievedList4);
+
+    auto* getList = celix_properties_getVersionArrayList(props, "array2", 
nullptr);
+    EXPECT_NE(array2, getList);
+    getList = celix_properties_getVersionArrayList(props, "array3", nullptr);
+    EXPECT_EQ(array3, getList);
+}
diff --git a/libs/utils/include/celix_properties.h 
b/libs/utils/include/celix_properties.h
index fc2c33a2..900b0d3c 100644
--- a/libs/utils/include/celix_properties.h
+++ b/libs/utils/include/celix_properties.h
@@ -68,7 +68,11 @@ typedef enum celix_properties_value_type {
     CELIX_PROPERTIES_VALUE_TYPE_DOUBLE = 3,    /**< Property value is a 
double. */
     CELIX_PROPERTIES_VALUE_TYPE_BOOL = 4,      /**< Property value is a 
boolean. */
     CELIX_PROPERTIES_VALUE_TYPE_VERSION = 5,   /**< Property value is a Celix 
version. */
-    CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY = 6 /**< Property value is an array 
of longs. */
+    CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY = 6, /**< Property value is an 
array of strings. */
+    CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY = 7, /**< Property value is an 
array of longs. */
+    CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY = 8, /**< Property value is an 
array of doubles. */
+    CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY = 9, /**< Property value is an 
array of booleans. */
+    CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY = 10, /**< Property value is an 
array of Celix versions. */
 } celix_properties_value_type_e;
 
 /**
@@ -254,7 +258,14 @@ CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assign(celix_properties_t* pr
                                                                   char* key,
                                                                   char* value);
 
-//TODO
+/**
+ * @Brief Get the value of a property, if the property is set and the 
underlying type is a long.
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
the value is not a long.
+ * @return The value of the property, or the default value if the property is 
not set or the value is not of the
+ * requested type.
+ */
 CELIX_UTILS_EXPORT long
 celix_properties_getLong(const celix_properties_t* properties, const char* 
key, long defaultValue);
 
@@ -285,7 +296,14 @@ celix_properties_getAsLong(const celix_properties_t* 
properties, const char* key
  */
 CELIX_UTILS_EXPORT celix_status_t celix_properties_setLong(celix_properties_t* 
properties, const char* key, long value);
 
-//TODO
+/**
+ * @Brief Get the value of a property, if the property is set and the 
underlying type is a boolean.
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
the value is not a boolean.
+ * @return The value of the property, or the default value if the property is 
not set or the value is not of the
+ * requested type.
+ */
 CELIX_UTILS_EXPORT bool
 celix_properties_getBool(const celix_properties_t* properties, const char* 
key, bool defaultValue);
 
@@ -331,7 +349,14 @@ CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setDouble(celix_properties_t*
                                                              const char* key,
                                                              double val);
 
-//TODO
+/**
+ * @Brief Get the value of a property, if the property is set and the 
underlying type is a double.
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
the value is not a double.
+ * @return The value of the property, or the default value if the property is 
not set or the value is not of the
+ * requested type.
+ */
 CELIX_UTILS_EXPORT double
 celix_properties_getDouble(const celix_properties_t* properties, const char* 
key, double defaultValue);
 
@@ -386,14 +411,14 @@ CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assignVersion(celix_propertie
                                                                  
celix_version_t* version);
 
 /**
- * @brief Peek at the Celix version value of a property without copying.
+ * @brief Get the Celix version value of a property without copying.
  *
  * This function provides a non-owning, read-only access to a Celix version 
contained in the properties.
  * It returns a const pointer to the Celix version value associated with the 
specified key.
  * This function does not perform any conversion from a string property value 
to a Celix version.
  *
  * @param[in] properties The property set to search.
- * @param[in] key The key of the property to peek at.
+ * @param[in] key The key of the property to get.
  * @param[in] defaultValue The value to return if the property is not set or 
if the value is not a Celix version.
  * @return A const pointer to the Celix version if it is present and valid, or 
the provided default value if the
  * property is not set or the value is not a valid Celix version. The returned 
pointer should not be modified or freed.
@@ -502,14 +527,14 @@ CELIX_UTILS_EXPORT celix_status_t 
celix_properties_getAsLongArrayList(const celi
                                                                   
celix_array_list_t** list);
 
 /**
- * @brief Peek at the property value as an array of longs without copying.
+ * @brief Get the property value as an array of longs without copying.
  *
  * This function provides a non-owning, read-only access to a property value 
interpreted as an array of longs.
  * It returns a const pointer to the array. If the property is not set or its 
value is not an array of longs,
  * the default value is returned.
  *
  * @param[in] properties The property set to search.
- * @param[in] key The key of the property to peek at.
+ * @param[in] key The key of the property to get.
  * @param[in] defaultValue The value to return if the property is not set or 
its value is not an array of longs.
  * @return A const pointer to the property value interpreted as an array of 
longs, or the default value if the property
  *         is not set or its value is not an array of longs. The returned 
pointer should not be modified or freed.
@@ -518,6 +543,401 @@ CELIX_UTILS_EXPORT const celix_array_list_t* 
celix_properties_getLongArrayList(c
                                                                             
const char* key,
                                                                             
const celix_array_list_t* defaultValue);
 
+/**
+ * @brief Set a double array value for a property.
+ *
+ * This function will make a copy of the provided celix_array_list_t object, 
assuming it contains double values,
+ * and store it in the property set.
+ * If an error occurs, the error status is returned and a message is logged to
+ * celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of double values to set for the property. 
Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key or values is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setDoubleArrayList(celix_properties_t* properties,
+                                                                    const 
char* key,
+                                                                    const 
celix_array_list_t* values);
+
+/**
+ * @brief Assign a double array value to a property, taking ownership of the 
array.
+ *
+ * This function stores a reference to the provided celix_array_list_t object 
in the property set and takes
+ * ownership of the array.
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of double values to assign to the property. 
Ownership of the array is transferred
+ *                   to the properties set. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL. On error, 
the values array list is destroyed.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assignDoubleArrayList(celix_properties_t* properties,
+                                                                       const 
char* key,
+                                                                       
celix_array_list_t* values);
+
+/**
+ * @brief Set multiple double values for a property using an array of longs.
+ *
+ * This function allows setting multiple double values for a given property 
key. The values are passed as an array
+ * of double integers. The number of values in the array should be specified 
by nrOfValues.
+ *
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] nrOfValues The number of double values in the array.
+ * @param[in] values An array of double values to set for the property. Cannot 
be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL or the 
values array is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setDoubles(celix_properties_t* properties,
+                                                            const char* key,
+                                                            const double* 
values,
+                                                            size_t nrOfValues);
+
+/**
+ * @brief Get a property value as an array of doubles, making a copy of the 
array.
+ *
+ * This function retrieves the value of a property, interpreting it as an 
array of doubles. It returns a new copy of the
+ * array. If the property is not set or its value is not an array of doubles, 
the default value is returned as a copy.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The default value to return if the property is not 
set or its value is not an array of
+ * doubles.
+ * @param[out] list A copy of the found list, a new array list with double 
values or a copy of the default value if the
+ *                 property is not set, its value is not an array doubles 
longs or its value cannot be converted to an
+ * array of doubles.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to create the
+ *        array list. Note if the key is not found, the return status is still 
CELIX_SUCCESS.
+ */
+CELIX_UTILS_EXPORT celix_status_t celix_properties_getAsDoubleArrayList(const 
celix_properties_t* properties,
+                                                                      const 
char* key,
+                                                                      const 
celix_array_list_t* defaultValue,
+                                                                      
celix_array_list_t** list);
+
+/**
+ * @brief Get the property value as an array of doubles without copying.
+ *
+ * This function provides a non-owning, read-only access to a property value 
interpreted as an array of doubles.
+ * It returns a const pointer to the array. If the property is not set or its 
value is not an array of doubles,
+ * the default value is returned.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
its value is not an array of doubles.
+ * @return A const pointer to the property value interpreted as an array of 
doubles, or the default value if the
+ * property is not set or its value is not an array of doubles. The returned 
pointer should not be modified or freed.
+ */
+CELIX_UTILS_EXPORT const celix_array_list_t* 
celix_properties_getDoubleArrayList(
+    const celix_properties_t* properties, const char* key, const 
celix_array_list_t* defaultValue);
+
+/**
+ * @brief Set a boolean array value for a property.
+ *
+ * This function will make a copy of the provided celix_array_list_t object, 
assuming it contains boolean values,
+ * and store it in the property set.
+ * If an error occurs, the error status is returned and a message is logged to
+ * celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of boolean values to set for the property. 
Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key or values is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setBoolArrayList(celix_properties_t* properties,
+                                                                      const 
char* key,
+                                                                      const 
celix_array_list_t* values);
+
+/**
+ * @brief Assign a boolean array value to a property, taking ownership of the 
array.
+ *
+ * This function stores a reference to the provided celix_array_list_t object 
in the property set and takes
+ * ownership of the array.
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of boolean values to assign to the 
property. Ownership of the array is transferred
+ *                   to the properties set. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL. On error, 
the values array list is destroyed.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assignBoolArrayList(celix_properties_t* properties,
+                                                                         const 
char* key,
+                                                                         
celix_array_list_t* values);
+
+/**
+ * @brief Set multiple boolean values for a property using an array of longs.
+ *
+ * This function allows setting multiple boolean values for a given property 
key. The values are passed as an array
+ * of booleans. The number of values in the array should be specified by 
nrOfValues.
+ *
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] nrOfValues The number of bool values in the array.
+ * @param[in] values An array of bool values to set for the property. Cannot 
be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL or the 
values array is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setBooleans(celix_properties_t* properties,
+                                                              const char* key,
+                                                              const bool* 
values,
+                                                              size_t 
nrOfValues);
+
+/**
+ * @brief Get a property value as an array of booleans, making a copy of the 
array.
+ *
+ * This function retrieves the value of a property, interpreting it as an 
array of booleans. It returns a new copy of the
+ * array. If the property is not set or its value is not an array of booleans, 
the default value is returned as a copy.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The default value to return if the property is not 
set or its value is not an array of
+ * booleans.
+ * @param[out] list A copy of the found list, a new array list with boolean 
values or a copy of the default value if the
+ *                 property is not set, its value is not an array of booleans 
or its value cannot be converted to an
+ * array of booleans.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to create the
+ *        array list. Note if the key is not found, the return status is still 
CELIX_SUCCESS.
+ */
+CELIX_UTILS_EXPORT celix_status_t celix_properties_getAsBoolArrayList(const 
celix_properties_t* properties,
+                                                                        const 
char* key,
+                                                                        const 
celix_array_list_t* defaultValue,
+                                                                        
celix_array_list_t** list);
+
+/**
+ * @brief Get the property value as an array of booleans without copying.
+ *
+ * This function provides a non-owning, read-only access to a property value 
interpreted as an array of booleans.
+ * It returns a const pointer to the array. If the property is not set or its 
value is not an array of booleans,
+ * the default value is returned.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
its value is not an array of booleans.
+ * @return A const pointer to the property value interpreted as an array of 
booleans, or the default value if the
+ * property is not set or its value is not an array of booleans. The returned 
pointer should not be modified or freed.
+ */
+CELIX_UTILS_EXPORT const celix_array_list_t* celix_properties_getBoolArrayList(
+    const celix_properties_t* properties, const char* key, const 
celix_array_list_t* defaultValue);
+
+/**
+ * @brief Set a string array value for a property.
+ *
+ * This function will make a copy of the provided celix_array_list_t object, 
assuming it contains string values,
+ * and store it in the property set.
+ * If an error occurs, the error status is returned and a message is logged to
+ * celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of string values to set for the property. 
Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key or values is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setStringArrayList(celix_properties_t* properties,
+                                                                    const 
char* key,
+                                                                    const 
celix_array_list_t* values);
+
+/**
+ * @brief Assign a string array value to a property, taking ownership of the 
array.
+ *
+ * The provided array list should be created with a remove callback so that 
the destruction of the array list
+ * will also free the strings in the array list. If this is not done, this 
property set will leak memory.
+ *
+ * This function stores a reference to the provided celix_array_list_t object 
in the property set and takes
+ * ownership of the array.
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of string values to assign to the property. 
Ownership of the array is transferred
+ *                   to the properties set. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL. On error, 
the values array list is destroyed.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assignStringArrayList(celix_properties_t* properties,
+                                                                       const 
char* key,
+                                                                       
celix_array_list_t* values);
+
+/**
+ * @brief Set multiple string values for a property using an array of longs.
+ *
+ * This function allows setting multiple string values for a given property 
key. The values are passed as an array
+ * of strings. The number of values in the array should be specified by 
nrOfValues.
+ *
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] nrOfValues The number of string values in the array.
+ * @param[in] values An array of string values to set for the property. Cannot 
be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL or the 
values array is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setStrings(celix_properties_t* properties,
+                                                               const char* key,
+                                                               const char** 
values,
+                                                               size_t 
nrOfValues);
+
+/**
+ * @brief Get a property value as an array of strings, making a copy of the 
array.
+ *
+ * This function retrieves the value of a property, interpreting it as an 
array of strings. It returns a new copy of the
+ * array. If the property is not set or its value is not an array of strings, 
the default value is returned as a copy.
+ *
+ * The returned array list is configured with a remove callback so that the 
destruction of the array list will also
+ * free the strings in the array list.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The default value to return if the property is not 
set or its value is not an array of
+ * strings.
+ * @param[out] list A copy of the found list, a new array list with string 
values or a copy of the default value if the
+ *                 property is not set, its value is not an array of strings 
or its value cannot be converted to an
+ * array of strings.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to create the
+ *        array list. Note if the key is not found, the return status is still 
CELIX_SUCCESS.
+ */
+CELIX_UTILS_EXPORT celix_status_t celix_properties_getAsStringArrayList(const 
celix_properties_t* properties,
+                                                                      const 
char* key,
+                                                                      const 
celix_array_list_t* defaultValue,
+                                                                      
celix_array_list_t** list);
+
+/**
+ * @brief Get the property value as an array of strings without copying.
+ *
+ * This function provides a non-owning, read-only access to a property value 
interpreted as an array of strings.
+ * It returns a const pointer to the array. If the property is not set or its 
value is not an array of strings,
+ * the default value is returned.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
its value is not an array of strings.
+ * @return A const pointer to the property value interpreted as an array of 
strings, or the default value if the
+ * property is not set or its value is not an array of strings. The returned 
pointer should not be modified or freed.
+ */
+CELIX_UTILS_EXPORT const celix_array_list_t* 
celix_properties_getStringArrayList(
+    const celix_properties_t* properties, const char* key, const 
celix_array_list_t* defaultValue);
+
+/**
+ * @brief Set a celix_version_t array value for a property.
+ *
+ * This function will make a copy of the provided celix_array_list_t object, 
assuming it contains celix_version_t
+ * values, and store it in the property set. If an error occurs, the error 
status is returned and a message is logged to
+ * celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of celix_version_t values to set for the 
property. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key or values is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setVersionArrayList(celix_properties_t* properties,
+                                                                       const 
char* key,
+                                                                       const 
celix_array_list_t* values);
+
+/**
+ * @brief Assign a celix_version_t array value to a property, taking ownership 
of the array.
+ *
+ * The provided array list should be created with a remove callback so that 
the destruction of the array list
+ * will also free the celix_version_t entries in the array list. If this is 
not done, this property set will leak
+ * memory.
+ *
+ * This function stores a reference to the provided celix_array_list_t object 
in the property set and takes
+ * ownership of the array.
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] values An array list of celix_version_t values to assign to the 
property. Ownership of the array is
+ * transferred to the properties set. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL. On error, 
the values array list is destroyed.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_assignVersionArrayList(celix_properties_t* properties,
+                                                                          
const char* key,
+                                                                          
celix_array_list_t* values);
+
+/**
+ * @brief Set multiple celix_version_t values for a property using an array of 
longs.
+ *
+ * This function allows setting multiple celix_version_t values for a given 
property key. The values are passed as an
+ * array with celix_version_t entries. The number of values in the array 
should be specified by nrOfValues.
+ *
+ * If an error occurs, the error status is returned, the provided array is 
destroyed and a
+ * message is logged to celix_err.
+ *
+ * @param[in] properties The property set to modify.
+ * @param[in] key The key of the property to set.
+ * @param[in] nrOfValues The number of celix_version_t values in the array.
+ * @param[in] values An array of celix_version_t values to set for the 
property. Cannot be NULL.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to set the entry,
+ *         and CELIX_ILLEGAL_ARGUMENT if the provided key is NULL or the 
values array is NULL.
+ */
+CELIX_UTILS_EXPORT celix_status_t 
celix_properties_setVersions(celix_properties_t* properties,
+                                                               const char* key,
+                                                               const 
celix_version_t** values,
+                                                               size_t 
nrOfValues);
+
+/**
+ * @brief Get a property value as an array of celix_version_t entries, making 
a copy of the array.
+ *
+ * This function retrieves the value of a property, interpreting it as an 
array of celix_version_t entries. It returns a
+ * new copy of the array. If the property is not set or its value is not an 
array of celix_version_t entries, the
+ * default value is returned as a copy.
+ *
+ * The returned array list is configured with a remove callback so that the 
destruction of the array list will also
+ * free the celix_version_t entries in the array list.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The default value to return if the property is not 
set or its value is not an array of
+ * celix_version_t entries.
+ * @param[out] list A copy of the found list, a new array list with 
celix_version_t values or a copy of the default
+ * value if the property is not set, its value is not an array of 
celix_version_t entries or its value cannot be
+ * converted to an array of celix_version_t entries.
+ * @return CELIX_SUCCESS if the operation was successful, CELIX_ENOMEM if 
there was not enough memory to create the
+ *        array list. Note if the key is not found, the return status is still 
CELIX_SUCCESS.
+ */
+CELIX_UTILS_EXPORT celix_status_t celix_properties_getAsVersionArrayList(const 
celix_properties_t* properties,
+                                                                         const 
char* key,
+                                                                         const 
celix_array_list_t* defaultValue,
+                                                                         
celix_array_list_t** list);
+
+/**
+ * @brief Get the property value as an array of celix_version_t entries 
without copying.
+ *
+ * This function provides a non-owning, read-only access to a property value 
interpreted as an array of celix_version_t
+ * entries. It returns a const pointer to the array. If the property is not 
set or its value is not an array of
+ * celix_version_t entries, the default value is returned.
+ *
+ * @param[in] properties The property set to search.
+ * @param[in] key The key of the property to get.
+ * @param[in] defaultValue The value to return if the property is not set or 
its value is not an array of
+ * celix_version_t entries.
+ * @return A const pointer to the property value interpreted as an array of 
celix_version_t entries, or the default
+ * value if the property is not set or its value is not an array of 
celix_version_t entries. The returned pointer should
+ * not be modified or freed.
+ */
+CELIX_UTILS_EXPORT const celix_array_list_t* 
celix_properties_getVersionArrayList(
+    const celix_properties_t* properties, const char* key, const 
celix_array_list_t* defaultValue);
+
 /**
  * @brief Set the value of a property based on the provided property entry, 
maintaining underlying type.
  *
diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c
index cafd092f..fc32350d 100644
--- a/libs/utils/src/properties.c
+++ b/libs/utils/src/properties.c
@@ -164,6 +164,14 @@ static celix_status_t 
celix_properties_fillEntry(celix_properties_t* properties,
         entry->value = entry->typed.boolValue ? 
CELIX_PROPERTIES_BOOL_TRUE_STRVAL : CELIX_PROPERTIES_BOOL_FALSE_STRVAL;
     } else if (prototype->valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY) 
{
         entry->value = 
celix_utils_longArrayListToString(entry->typed.arrayValue);
+    } else if (prototype->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY) {
+        entry->value = 
celix_utils_doubleArrayListToString(entry->typed.arrayValue);
+    } else if (prototype->valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY) 
{
+        entry->value = 
celix_utils_boolArrayListToString(entry->typed.arrayValue);
+    } else if (prototype->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY) {
+        entry->value = 
celix_utils_stringArrayListToString(entry->typed.arrayValue);
+    } else if (prototype->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY) {
+        entry->value = 
celix_utils_versionArrayListToString(entry->typed.arrayValue);
     } else /*string value*/ {
         assert(prototype->valueType == CELIX_PROPERTIES_VALUE_TYPE_STRING);
         entry->value = celix_properties_createString(properties, 
prototype->typed.strValue);
@@ -186,7 +194,9 @@ celix_properties_entry_t* 
celix_properties_allocEntry(celix_properties_t* proper
     } else {
         entry = malloc(sizeof(*entry));
     }
-    memset(entry, 0, sizeof(*entry));
+    if (entry) {
+        memset(entry, 0, sizeof(*entry));
+    }
     return entry;
 }
 
@@ -211,6 +221,16 @@ static void celix_properties_freeTypedEntry(const 
celix_properties_entry_t* entr
             celix_version_destroy((celix_version_t*)entry->typed.versionValue);
     } else if (entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY) {
             
celix_arrayList_destroy((celix_array_list_t*)entry->typed.arrayValue);
+    } else if (entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY) {
+            
celix_arrayList_destroy((celix_array_list_t*)entry->typed.arrayValue);
+    } else if (entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY) {
+            
celix_arrayList_destroy((celix_array_list_t*)entry->typed.arrayValue);
+    } else if (entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY) {
+            
celix_arrayList_destroy((celix_array_list_t*)entry->typed.arrayValue);
+    } else if (entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY) {
+            
celix_arrayList_destroy((celix_array_list_t*)entry->typed.arrayValue);
+    } else {
+        // nop
     }
 }
 
@@ -721,6 +741,14 @@ void celix_properties_unset(celix_properties_t* 
properties, const char* key) {
     }
 }
 
+long celix_properties_getLong(const celix_properties_t* properties, const 
char* key, long defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG) 
{
+        return entry->typed.longValue;
+    }
+    return defaultValue;
+}
+
 long celix_properties_getAsLong(const celix_properties_t* props, const char* 
key, long defaultValue) {
     celix_properties_entry_t* entry = celix_properties_getEntry(props, key);
     if (entry != NULL && entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG) 
{
@@ -740,6 +768,14 @@ celix_status_t 
celix_properties_setLong(celix_properties_t* props, const char* k
     return celix_properties_createAndSetEntry(props, key, &prototype);
 }
 
+double celix_properties_getDouble(const celix_properties_t* properties, const 
char* key, double defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE) {
+        return entry->typed.doubleValue;
+    }
+    return defaultValue;
+}
+
 double celix_properties_getAsDouble(const celix_properties_t* props, const 
char* key, double defaultValue) {
     celix_properties_entry_t* entry = celix_properties_getEntry(props, key);
     if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE) {
@@ -757,6 +793,14 @@ celix_status_t 
celix_properties_setDouble(celix_properties_t* props, const char*
     return celix_properties_createAndSetEntry(props, key, &prototype);
 }
 
+bool celix_properties_getBool(const celix_properties_t* properties, const 
char* key, bool defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL) 
{
+        return entry->typed.boolValue;
+    }
+    return defaultValue;
+}
+
 bool celix_properties_getAsBool(const celix_properties_t* props, const char* 
key, bool defaultValue) {
     celix_properties_entry_t* entry = celix_properties_getEntry(props, key);
     if (entry != NULL && entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL) 
{
@@ -839,9 +883,9 @@ celix_properties_assignVersion(celix_properties_t* 
properties, const char* key,
 }
 
 celix_status_t celix_properties_getAsLongArrayList(const celix_properties_t* 
properties,
-                                                                       const 
char* key,
-                                                                       const 
celix_array_list_t* defaultValue,
-                                                                       
celix_array_list_t** list) {
+                                                   const char* key,
+                                                   const celix_array_list_t* 
defaultValue,
+                                                   celix_array_list_t** list) {
     celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
     if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY) {
         celix_array_list_t* copy = 
celix_arrayList_copy(entry->typed.arrayValue);
@@ -854,7 +898,7 @@ celix_status_t celix_properties_getAsLongArrayList(const 
celix_properties_t* pro
     if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
         celix_status_t convertStatus = 
celix_utils_convertStringToLongArrayList(entry->value, defaultValue, list);
         if (convertStatus == CELIX_ILLEGAL_ARGUMENT) {
-            //conversion failed, but no memory error so defaultValue is copied 
and set
+            // conversion failed, but no memory error so defaultValue is 
copied and set
             return CELIX_SUCCESS;
         }
         return convertStatus;
@@ -869,17 +913,38 @@ celix_status_t celix_properties_getAsLongArrayList(const 
celix_properties_t* pro
 
 celix_status_t
 celix_properties_setLongArrayList(celix_properties_t* properties, const char* 
key, const celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_array_list_t* copy = celix_arrayList_copy(values);
+    if (!copy) {
+        return CELIX_ENOMEM;
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY;
+    prototype.typed.arrayValue = copy;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_assignLongArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY;
+    prototype.typed.arrayValue = values;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_setLongs(celix_properties_t* properties, const char* key, 
const long* values, size_t nrOfValues) {
     assert(values != NULL);
     celix_autoptr(celix_array_list_t) copy = celix_arrayList_create();
     if (!copy) {
         celix_err_push("Failed to create a long array");
         return CELIX_ENOMEM;
     }
-    for (int i = 0; values && i < celix_arrayList_size(values); ++i) {
-        long val = celix_arrayList_getLong(values, i);
-        celix_status_t status = celix_arrayList_addLong(copy, val);
+    for (size_t i = 0; i < nrOfValues; ++i) {
+        celix_status_t status = celix_arrayList_addLong(copy, values[i]);
         if (status != CELIX_SUCCESS) {
-            celix_err_pushf("Failed to add long to array list. Got error %i", 
status);
+            celix_err_push("Failed to add long to array list");
             return status;
         }
     }
@@ -890,43 +955,431 @@ celix_properties_setLongArrayList(celix_properties_t* 
properties, const char* ke
     return celix_properties_createAndSetEntry(properties, key, &prototype);
 }
 
+const celix_array_list_t* celix_properties_getLongArrayList(const 
celix_properties_t* properties,
+                                                            const char* key,
+                                                            const 
celix_array_list_t* defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY) {
+        return entry->typed.arrayValue;
+    }
+    return defaultValue;
+}
+
 celix_status_t
-celix_properties_assignLongArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+celix_properties_setDoubleArrayList(celix_properties_t* properties, const 
char* key, const celix_array_list_t* values) {
     assert(values != NULL);
+    celix_array_list_t* copy = celix_arrayList_copy(values);
+    if (!copy) {
+        return CELIX_ENOMEM;
+    }
     celix_properties_entry_t prototype = {0};
-    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY;
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY;
+    prototype.typed.arrayValue = copy;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_assignDoubleArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY;
     prototype.typed.arrayValue = values;
     return celix_properties_createAndSetEntry(properties, key, &prototype);
 }
 
 celix_status_t
-celix_properties_setLongs(celix_properties_t* properties, const char* key, 
const long* values, size_t nrOfValues) {
+celix_properties_setDoubles(celix_properties_t* properties, const char* key, 
const double* values, size_t nrOfValues) {
     assert(values != NULL);
     celix_autoptr(celix_array_list_t) copy = celix_arrayList_create();
     if (!copy) {
-        celix_err_push("Failed to create a long array");
+        celix_err_push("Failed to create a double array");
         return CELIX_ENOMEM;
     }
     for (size_t i = 0; i < nrOfValues; ++i) {
-        long val = values[i];
-        celix_status_t status = celix_arrayList_addLong(copy, val);
+        celix_status_t status = celix_arrayList_addDouble(copy, values[i]);
         if (status != CELIX_SUCCESS) {
-            celix_err_pushf("Failed to add long to array list. Got error %i", 
status);
+            celix_err_push("Failed to add double to array list");
             return status;
         }
     }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY;
+    prototype.typed.arrayValue = celix_steal_ptr(copy);
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
 
+celix_status_t celix_properties_getAsDoubleArrayList(const celix_properties_t* 
properties,
+                                                     const char* key,
+                                                     const celix_array_list_t* 
defaultValue,
+                                                     celix_array_list_t** 
list) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY) {
+        celix_array_list_t* copy = 
celix_arrayList_copy(entry->typed.arrayValue);
+        if (!copy) {
+            return CELIX_ENOMEM;
+        }
+        *list = copy;
+        return CELIX_SUCCESS;
+    }
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        celix_status_t convertStatus = 
celix_utils_convertStringToDoubleArrayList(entry->value, defaultValue, list);
+        if (convertStatus == CELIX_ILLEGAL_ARGUMENT) {
+            // conversion failed, but no memory error so defaultValue is 
copied and set
+            return CELIX_SUCCESS;
+        }
+        return convertStatus;
+    }
+    if (defaultValue) {
+        *list = celix_arrayList_copy(defaultValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    *list = NULL;
+    return CELIX_SUCCESS;
+}
+
+const celix_array_list_t* celix_properties_getDoubleArrayList(const 
celix_properties_t* properties,
+                                                              const char* key,
+                                                              const 
celix_array_list_t* defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE_ARRAY) {
+        return entry->typed.arrayValue;
+    }
+    return defaultValue;
+}
+
+celix_status_t celix_properties_setBoolArrayList(celix_properties_t* 
properties, const char* key, const celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_array_list_t* copy = celix_arrayList_copy(values);
+    if (!copy) {
+        return CELIX_ENOMEM;
+    }
     celix_properties_entry_t prototype = {0};
-    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY;
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY;
+    prototype.typed.arrayValue = copy;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_assignBoolArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY;
+    prototype.typed.arrayValue = values;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_setBooleans(celix_properties_t* properties, const char* key, 
const bool* values, size_t nrOfValues) {
+    assert(values != NULL);
+    celix_autoptr(celix_array_list_t) copy = celix_arrayList_create();
+    if (!copy) {
+        celix_err_push("Failed to create a bool array");
+        return CELIX_ENOMEM;
+    }
+    for (size_t i = 0; i < nrOfValues; ++i) {
+        celix_status_t status = celix_arrayList_addBool(copy, values[i]);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add bool to array list.");
+            return status;
+        }
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY;
     prototype.typed.arrayValue = celix_steal_ptr(copy);
     return celix_properties_createAndSetEntry(properties, key, &prototype);
 }
 
-const celix_array_list_t* celix_properties_getLongArrayList(const 
celix_properties_t* properties,
-                                                         const char* key,
-                                                         const 
celix_array_list_t* defaultValue) {
+celix_status_t celix_properties_getAsBoolArrayList(const celix_properties_t* 
properties,
+                                                     const char* key,
+                                                     const celix_array_list_t* 
defaultValue,
+                                                     celix_array_list_t** 
list) {
     celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
-    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_LONG_ARRAY) {
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY) {
+        celix_array_list_t* copy = 
celix_arrayList_copy(entry->typed.arrayValue);
+        if (!copy) {
+            return CELIX_ENOMEM;
+        }
+        *list = copy;
+        return CELIX_SUCCESS;
+    }
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        celix_status_t convertStatus = 
celix_utils_convertStringToBoolArrayList(entry->value, defaultValue, list);
+        if (convertStatus == CELIX_ILLEGAL_ARGUMENT) {
+            // conversion failed, but no memory error so defaultValue is 
copied and set
+            return CELIX_SUCCESS;
+        }
+        return convertStatus;
+    }
+    if (defaultValue) {
+        *list = celix_arrayList_copy(defaultValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    *list = NULL;
+    return CELIX_SUCCESS;
+}
+
+const celix_array_list_t* celix_properties_getBoolArrayList(const 
celix_properties_t* properties,
+                                                              const char* key,
+                                                              const 
celix_array_list_t* defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_BOOL_ARRAY) {
+        return entry->typed.arrayValue;
+    }
+    return defaultValue;
+}
+
+celix_status_t celix_properties_setStringArrayList(celix_properties_t* 
properties, const char* key, const celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = free;
+    opts.initialCapacity = celix_arrayList_size(values);
+    celix_autoptr(celix_array_list_t) list = 
celix_arrayList_createWithOptions(&opts);
+    if (!list) {
+        celix_err_push("Failed to create a string array");
+        return CELIX_ENOMEM;
+    }
+    for (int i = 0 ; i < celix_arrayList_size(values); ++i) {
+        const char* val = celix_arrayList_get(values, i);
+        char* copy = celix_utils_strdup(val);
+        if (!copy) {
+            celix_err_push("Failed to duplicate string");
+            return CELIX_ENOMEM;
+        }
+        celix_status_t status = celix_arrayList_add(list, copy);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add string to array list");
+            return status;
+        }
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY;
+    prototype.typed.arrayValue = celix_steal_ptr(list);
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_assignStringArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY;
+    prototype.typed.arrayValue = values;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_setStrings(celix_properties_t* properties, const char* key, 
const char** values, size_t nrOfValues) {
+    assert(values != NULL);
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = free;
+    opts.initialCapacity = nrOfValues;
+    celix_autoptr(celix_array_list_t) list = 
celix_arrayList_createWithOptions(&opts);
+    if (!list) {
+        celix_err_push("Failed to create a string array");
+        return CELIX_ENOMEM;
+    }
+    for (size_t i = 0; i < nrOfValues; ++i) {
+        char* copy = celix_utils_strdup(values[i]);
+        if (!copy) {
+            celix_err_push("Failed to duplicate string");
+            return CELIX_ENOMEM;
+        }
+        celix_status_t status = celix_arrayList_addString(list, copy);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add string to array list");
+            return status;
+        }
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY;
+    prototype.typed.arrayValue = celix_steal_ptr(list);
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_array_list_t* celix_properties_deepCopyStringArrayList(const 
celix_array_list_t* list) {
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = free;
+    opts.initialCapacity = celix_arrayList_size(list);
+    celix_autoptr(celix_array_list_t) copy = 
celix_arrayList_createWithOptions(&opts);
+    if (!copy) {
+        celix_err_push("Failed to create a string array");
+        return NULL;
+    }
+    for (int i = 0 ; i < celix_arrayList_size(list); ++i) {
+        const char* val = celix_arrayList_get(list, i);
+        char* copyStr = celix_utils_strdup(val);
+        if (!copyStr) {
+            celix_err_push("Failed to duplicate string");
+            return NULL;
+        }
+        celix_status_t status = celix_arrayList_addString(copy, copyStr);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add string to array list");
+            return NULL;
+        }
+    }
+    return celix_steal_ptr(copy);
+}
+
+celix_status_t celix_properties_getAsStringArrayList(const celix_properties_t* 
properties,
+                                                   const char* key,
+                                                   const celix_array_list_t* 
defaultValue,
+                                                   celix_array_list_t** list) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY) {
+        *list = 
celix_properties_deepCopyStringArrayList(entry->typed.arrayValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        celix_status_t convertStatus = 
celix_utils_convertStringToStringArrayList(entry->value, defaultValue, list);
+        if (convertStatus == CELIX_ILLEGAL_ARGUMENT) {
+            // conversion failed, but no memory error so defaultValue is 
copied and set
+            return CELIX_SUCCESS;
+        }
+        return convertStatus;
+    }
+    if (defaultValue) {
+        *list = celix_properties_deepCopyStringArrayList(defaultValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    *list = NULL;
+    return CELIX_SUCCESS;
+}
+
+const celix_array_list_t* celix_properties_getStringArrayList(const 
celix_properties_t* properties,
+                                                            const char* key,
+                                                            const 
celix_array_list_t* defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING_ARRAY) {
+        return entry->typed.arrayValue;
+    }
+    return defaultValue;
+}
+
+static void celix_properties_destroyVersionCallback(void *data) {
+    celix_version_destroy((celix_version_t*)data);
+}
+
+celix_status_t celix_properties_setVersionArrayList(celix_properties_t* 
properties, const char* key, const celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = celix_properties_destroyVersionCallback;
+    opts.initialCapacity = celix_arrayList_size(values);
+    celix_autoptr(celix_array_list_t) list = 
celix_arrayList_createWithOptions(&opts);
+    if (!list) {
+        celix_err_push("Failed to create a version array");
+        return CELIX_ENOMEM;
+    }
+    for (int i = 0 ; i < celix_arrayList_size(values); ++i) {
+        celix_version_t* version = celix_arrayList_get(values, i);
+        celix_version_t* copy = celix_version_copy(version);
+        if (!copy) {
+            celix_err_push("Failed to duplicate version");
+            return CELIX_ENOMEM;
+        }
+        celix_status_t status = celix_arrayList_add(list, copy);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add version to array list");
+            return status;
+        }
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY;
+    prototype.typed.arrayValue = celix_steal_ptr(list);
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_assignVersionArrayList(celix_properties_t* properties, const 
char* key, celix_array_list_t* values) {
+    assert(values != NULL);
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY;
+    prototype.typed.arrayValue = values;
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+celix_status_t
+celix_properties_setVersions(celix_properties_t* properties, const char* key, 
const celix_version_t** values, size_t nrOfValues) {
+    assert(values != NULL);
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = free;
+    opts.initialCapacity = nrOfValues;
+    celix_autoptr(celix_array_list_t) list = 
celix_arrayList_createWithOptions(&opts);
+    if (!list) {
+        celix_err_push("Failed to create a version array");
+        return CELIX_ENOMEM;
+    }
+    for (size_t i = 0; i < nrOfValues; ++i) {
+        celix_version_t* copy = celix_version_copy(values[i]);
+        if (!copy) {
+            celix_err_push("Failed to duplicate version");
+            return CELIX_ENOMEM;
+        }
+        celix_status_t status = celix_arrayList_add(list, copy);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add version to array list");
+            return status;
+        }
+    }
+    celix_properties_entry_t prototype = {0};
+    prototype.valueType = CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY;
+    prototype.typed.arrayValue = celix_steal_ptr(list);
+    return celix_properties_createAndSetEntry(properties, key, &prototype);
+}
+
+static celix_array_list_t* celix_properties_deepCopyVersionArrayList(const 
celix_array_list_t* list) {
+    celix_array_list_create_options_t opts = 
CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.simpleRemovedCallback = celix_properties_destroyVersionCallback;
+    opts.initialCapacity = celix_arrayList_size(list);
+    celix_autoptr(celix_array_list_t) copy = 
celix_arrayList_createWithOptions(&opts);
+    if (!copy) {
+        return NULL;
+    }
+    for (int i = 0; i < celix_arrayList_size(list); ++i) {
+        const celix_version_t* val = celix_arrayList_get(list, i);
+        celix_version_t* verCopy = celix_version_copy(val);
+        if (!verCopy) {
+            celix_err_push("Failed to duplicate version");
+            return NULL;
+        }
+        celix_status_t status = celix_arrayList_add(copy, verCopy);
+        if (status != CELIX_SUCCESS) {
+            celix_err_push("Failed to add version to array list");
+            return NULL;
+        }
+    }
+    return celix_steal_ptr(copy);
+}
+
+celix_status_t celix_properties_getAsVersionArrayList(const 
celix_properties_t* properties,
+                                                     const char* key,
+                                                     const celix_array_list_t* 
defaultValue,
+                                                     celix_array_list_t** 
list) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY) {
+        *list = 
celix_properties_deepCopyVersionArrayList(entry->typed.arrayValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        celix_status_t convertStatus = 
celix_utils_convertStringToStringArrayList(entry->value, defaultValue, list);
+        if (convertStatus == CELIX_ILLEGAL_ARGUMENT) {
+            // conversion failed, but no memory error so defaultValue is 
copied and set
+            return CELIX_SUCCESS;
+        }
+        return convertStatus;
+    }
+    if (defaultValue) {
+        *list = celix_properties_deepCopyVersionArrayList(defaultValue);
+        return *list ? CELIX_SUCCESS : CELIX_ENOMEM;
+    }
+    *list = NULL;
+    return CELIX_SUCCESS;
+}
+
+const celix_array_list_t* celix_properties_getVersionArrayList(const 
celix_properties_t* properties,
+                                                              const char* key,
+                                                              const 
celix_array_list_t* defaultValue) {
+    celix_properties_entry_t* entry = celix_properties_getEntry(properties, 
key);
+    if (entry != NULL && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_VERSION_ARRAY) {
         return entry->typed.arrayValue;
     }
     return defaultValue;

Reply via email to