diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a28090..8cf8920 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# CHANGELOG
+## v2.1.3
+
+### Date: 06-Jun-2025
+
+- Fixed SyncStack to handle ArrayList
+
## v2.1.2
### Date: 26-May-2025
diff --git a/pom.xml b/pom.xml
index 7aa3656..dcf1628 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
com.contentstack.sdk
java
- 2.1.2
+ 2.1.3
jar
contentstack-java
Java SDK for Contentstack Content Delivery API
diff --git a/src/main/java/com/contentstack/sdk/SyncStack.java b/src/main/java/com/contentstack/sdk/SyncStack.java
index 49308ad..b83fd86 100755
--- a/src/main/java/com/contentstack/sdk/SyncStack.java
+++ b/src/main/java/com/contentstack/sdk/SyncStack.java
@@ -1,11 +1,13 @@
package com.contentstack.sdk;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import java.util.logging.Logger;
@@ -68,6 +70,7 @@ protected synchronized void setJSON(@NotNull JSONObject jsonobject) {
if (receiveJson.has("items")) {
Object itemsObj = receiveJson.opt("items");
+
if (itemsObj instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) itemsObj;
syncItems = new ArrayList<>();
@@ -77,14 +80,26 @@ protected synchronized void setJSON(@NotNull JSONObject jsonobject) {
syncItems.add(sanitizeJson(jsonItem));
}
}
- } else {
- if (itemsObj instanceof JSONObject) {
- syncItems = new ArrayList<>();
- syncItems.add(sanitizeJson((JSONObject) itemsObj));
- } else {
- logger.warning("'items' is not a valid list. Skipping processing.");
- syncItems = new ArrayList<>();
+ } else if (itemsObj instanceof JSONObject) {
+ syncItems = new ArrayList<>();
+ syncItems.add(sanitizeJson((JSONObject) itemsObj));
+ } else if (itemsObj instanceof List) {
+ List> itemsList = (List>) itemsObj;
+ syncItems = new ArrayList<>();
+ for (Object item : itemsList) {
+ if (item instanceof JSONObject) {
+ syncItems.add(sanitizeJson((JSONObject) item));
+ } else if (item instanceof Map) {
+ JSONObject jsonItem = new JSONObject((Map, ?>) item);
+ syncItems.add(sanitizeJson(jsonItem));
+ } else {
+ logger.warning("Item in ArrayList is not a JSONObject or LinkedHashMap. Skipping. Type: " + item.getClass().getName());
+ }
}
+ } else {
+ logger.warning("'items' is not a valid JSONArray, JSONObject, or ArrayList. Type: " +
+ (itemsObj != null ? itemsObj.getClass().getName() : "null"));
+ syncItems = new ArrayList<>();
}
} else {
syncItems = new ArrayList<>();
diff --git a/src/test/java/com/contentstack/sdk/TestSyncStack.java b/src/test/java/com/contentstack/sdk/TestSyncStack.java
index cdd1a62..42e5acd 100644
--- a/src/test/java/com/contentstack/sdk/TestSyncStack.java
+++ b/src/test/java/com/contentstack/sdk/TestSyncStack.java
@@ -6,9 +6,15 @@
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
public class TestSyncStack {
private SyncStack syncStack;
+ private final Stack stack = Credentials.getStack();
+ private final String host = Credentials.HOST;
@BeforeEach
void setUp() {
@@ -176,4 +182,37 @@ void testSetJSON_ThreadSafety() throws InterruptedException {
assertFalse(syncStack.getItems().isEmpty()); // No race conditions
}
+
+ /**
+ * ✅ Test: Real API call to syncContentType
+ */
+ @Test
+ void testRealSyncContentType() throws IllegalAccessException {
+ // Create a CountDownLatch to wait for the async call to complete
+ CountDownLatch latch = new CountDownLatch(1);
+ // Make the actual API call
+ stack.syncContentType("product", new SyncResultCallBack() {
+ @Override
+ public void onCompletion(SyncStack syncStack, Error error) {
+ if (error != null) {
+ fail("Sync failed with error: " + error.getErrorMessage());
+ }
+ // Verify the response
+ assertNotNull(syncStack.getJSONResponse());
+ assertNull(syncStack.getUrl());
+ assertNotNull(syncStack.getItems());
+ assertFalse(syncStack.getItems().isEmpty());
+ assertTrue(syncStack.getCount() > 0);
+
+ latch.countDown();
+ }
+ });
+
+ try {
+ // Wait for the async call to complete (with timeout)
+ assertTrue(latch.await(10, TimeUnit.SECONDS), "Sync operation timed out");
+ } catch (InterruptedException e) {
+ fail("Test was interrupted: " + e.getMessage());
+ }
+ }
}