diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/service/ResolutionHelper.java b/fineract-core/src/main/java/org/apache/fineract/batch/service/ResolutionHelper.java index 332041706..672f7927c 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/service/ResolutionHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/service/ResolutionHelper.java @@ -25,6 +25,8 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.ReadContext; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -134,7 +136,7 @@ public class ResolutionHelper { // parameter for (Map.Entry element : jsonRequestBody.entrySet()) { final String key = element.getKey(); - final JsonElement value = resolveDependentVariables(element.getValue(), responseCtx); + final JsonElement value = resolveDependentVariables(element.getValue(), requestBody, responseCtx); jsonResultBody.add(key, value); } // Set the body after dependency resolution @@ -163,44 +165,51 @@ public class ResolutionHelper { return request; } - private JsonElement resolveDependentVariables(final JsonElement jsonElement, final ReadContext responseCtx) { + private JsonElement resolveDependentVariables(final JsonElement jsonElement, final String requestBody, final ReadContext responseCtx) { JsonElement value; if (jsonElement.isJsonObject()) { final JsonObject jsObject = jsonElement.getAsJsonObject(); - value = processJsonObject(jsObject, responseCtx); + value = processJsonObject(jsObject, requestBody, responseCtx); } else if (jsonElement.isJsonArray()) { final JsonArray jsElementArray = jsonElement.getAsJsonArray(); - value = processJsonArray(jsElementArray, responseCtx); + value = processJsonArray(jsElementArray, requestBody, responseCtx); } else if (jsonElement.isJsonNull()) { // No further processing of null values value = jsonElement; } else { - value = processJsonPrimitive(jsonElement, responseCtx); + value = processJsonPrimitive(jsonElement, requestBody, responseCtx); } return value; } - private JsonElement processJsonObject(final JsonObject jsObject, final ReadContext responseCtx) { + private JsonElement processJsonObject(final JsonObject jsObject, final String requestBody, final ReadContext responseCtx) { JsonObject valueObj = new JsonObject(); for (Map.Entry element : jsObject.entrySet()) { - valueObj.add(element.getKey(), resolveDependentVariables(element.getValue(), responseCtx)); + valueObj.add(element.getKey(), resolveDependentVariables(element.getValue(), requestBody, responseCtx)); } return valueObj; } - private JsonArray processJsonArray(final JsonArray elementArray, final ReadContext responseCtx) { + private JsonArray processJsonArray(final JsonArray elementArray, final String requestBody, final ReadContext responseCtx) { JsonArray valueArr = new JsonArray(); for (JsonElement element : elementArray) { - valueArr.add(resolveDependentVariables(element, responseCtx)); + valueArr.add(resolveDependentVariables(element, requestBody, responseCtx)); } return valueArr; } - private JsonElement processJsonPrimitive(final JsonElement element, final ReadContext responseCtx) { + private JsonElement processJsonPrimitive(final JsonElement element, final String requestBody, final ReadContext responseCtx) { JsonElement value = element; if (element instanceof JsonPrimitive) { String paramVal = element.getAsString(); - if (paramVal.contains("$.")) { + if (paramVal.contains("$[ARRAYDATE]")) { + String resolvableParamVal = paramVal.replace("$[ARRAYDATE]", "$"); + final String resParamValue = responseCtx.read(resolvableParamVal).toString(); + JsonArray date = (JsonArray) this.fromJsonHelper.parse(resParamValue); + String dateFormat = JsonPath.read(requestBody, "$.dateFormat"); + return new JsonPrimitive(DateTimeFormatter.ofPattern(dateFormat) + .format(LocalDate.of(date.get(0).getAsInt(), date.get(1).getAsInt(), date.get(2).getAsInt()))); + } else if (paramVal.contains("$.")) { // Get the value of the parameter from parent response final String resParamValue = responseCtx.read(paramVal).toString(); value = this.fromJsonHelper.parse(resParamValue); diff --git a/fineract-core/src/test/java/org/apache/fineract/batch/service/ResolutionHelperTest.java b/fineract-core/src/test/java/org/apache/fineract/batch/service/ResolutionHelperTest.java index 1a735b9d6..fcccb567d 100644 --- a/fineract-core/src/test/java/org/apache/fineract/batch/service/ResolutionHelperTest.java +++ b/fineract-core/src/test/java/org/apache/fineract/batch/service/ResolutionHelperTest.java @@ -21,6 +21,7 @@ package org.apache.fineract.batch.service; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -104,4 +105,93 @@ public class ResolutionHelperTest { assertEquals("{\"key1\":\"value1\",\"key2\":{\"subKey\":false},\"key3\":[1,2,3],\"key4\":null}", resolvedRequest.getBody()); assertEquals("/resource/id", resolvedRequest.getRelativeUrl()); } + + @Test + void testResolveRequestWithArrayDateParameter() { + // Test resolving a JSON primitive with array date format + BatchRequest batchRequest = new BatchRequest(); + batchRequest + .setBody("{\"dateFormat\":\"dd MMMM yyyy\",\"startDate\":\"$[ARRAYDATE].dates[0]\",\"endDate\":\"$[ARRAYDATE].dates[1]\"}"); + batchRequest.setRelativeUrl("/resource/endpoint"); + + BatchResponse parentResponse = new BatchResponse(); + parentResponse.setBody("{\"dates\":[[2023,5,15],[2023,6,15]]}"); + + // Mock the response context + ReadContext readContext = mock(ReadContext.class); + when(readContext.read("$.dates[0]")).thenReturn(new int[] { 2023, 5, 15 }); + when(readContext.read("$.dates[1]")).thenReturn(new int[] { 2023, 6, 15 }); + + BatchRequest resolvedRequest = resolutionHelper.resolveRequest(batchRequest, parentResponse); + assertNotNull(resolvedRequest); + + // Check for possible date formats + String body = resolvedRequest.getBody(); + assertTrue(body.contains("\"startDate\":\"15 May 2023\"") || body.contains("\"startDate\":\"15 May, 2023\"") + || body.contains("\"startDate\":\"15 May. 2023\"") || body.contains("\"startDate\":\"May 15, 2023\"")); + assertTrue(body.contains("\"endDate\":\"15 June 2023\"") || body.contains("\"endDate\":\"15 June, 2023\"") + || body.contains("\"endDate\":\"15 Jun. 2023\"") || body.contains("\"endDate\":\"June 15, 2023\"")); + } + + @Test + void testResolveRequestWithNestedJsonPrimitives() { + // Test resolving nested JSON primitives + BatchRequest batchRequest = new BatchRequest(); + batchRequest.setBody("{\"nested\":{\"key1\":\"$.value1\",\"key2\":123,\"key3\":true,\"key4\":null}}"); + batchRequest.setRelativeUrl("/resource/endpoint"); + + BatchResponse parentResponse = new BatchResponse(); + parentResponse.setBody("{\"value1\":\"resolvedValue\"}"); + + // Mock the response context + ReadContext readContext = mock(ReadContext.class); + when(readContext.read("$.value1")).thenReturn("resolvedValue"); + + BatchRequest resolvedRequest = resolutionHelper.resolveRequest(batchRequest, parentResponse); + assertNotNull(resolvedRequest); + assertEquals("{\"nested\":{\"key1\":\"resolvedValue\",\"key2\":123,\"key3\":true,\"key4\":null}}", resolvedRequest.getBody()); + } + + @Test + void testResolveRequestWithPrimitiveTypes() { + // Test resolving different primitive types + BatchRequest batchRequest = new BatchRequest(); + batchRequest.setBody("{\"string\":\"text\",\"number\":123.45,\"boolean\":true,\"nullValue\":null}"); + batchRequest.setRelativeUrl("/resource/endpoint"); + + BatchResponse parentResponse = new BatchResponse(); + parentResponse.setBody("{}"); // Empty response as we're not using any references + + BatchRequest resolvedRequest = resolutionHelper.resolveRequest(batchRequest, parentResponse); + assertNotNull(resolvedRequest); + + // The JSON might be reordered, so we need to check for existence of each key-value pair + String body = resolvedRequest.getBody(); + assertTrue(body.contains("\"string\":\"text\"")); + assertTrue(body.contains("\"number\":123.45")); + assertTrue(body.contains("\"boolean\":true")); + assertTrue(body.contains("\"nullValue\":null")); + } + + @Test + void testResolveRequestWithComplexReferencePath() { + // Test resolving with complex reference paths + BatchRequest batchRequest = new BatchRequest(); + batchRequest.setBody("{\"user\": {\"name\": \"$.userData.name\",\"age\": \"$.userData.age\"}}"); + batchRequest.setRelativeUrl("/users/$.userData.id"); + + BatchResponse parentResponse = new BatchResponse(); + parentResponse.setBody("{\"userData\":{\"id\": 42,\"name\": \"John\",\"age\": 30}}"); + + // Mock the response context + ReadContext readContext = mock(ReadContext.class); + when(readContext.read("$.userData.name")).thenReturn("John"); + when(readContext.read("$.userData.age")).thenReturn(30); + when(readContext.read("$.userData.id")).thenReturn(42); + + BatchRequest resolvedRequest = resolutionHelper.resolveRequest(batchRequest, parentResponse); + assertNotNull(resolvedRequest); + assertEquals("{\"user\":{\"name\":\"John\",\"age\":30}}", resolvedRequest.getBody()); + assertEquals("/users/42", resolvedRequest.getRelativeUrl()); + } }