From 9ad61ac6e0f346b4083119e33a8d157a5b8bbe53 Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Sat, 16 Aug 2025 14:42:35 +0500 Subject: [PATCH 1/6] chore(deps): remove javax and replacing it by jackson --- pom.xml | 73 +++--- src/main/java/io/apimatic/core/ErrorCase.java | 41 ++-- .../apimatic/core/utilities/CoreHelper.java | 211 +++++++++--------- 3 files changed, 145 insertions(+), 180 deletions(-) diff --git a/pom.xml b/pom.xml index 43837446..b9f01376 100644 --- a/pom.xml +++ b/pom.xml @@ -35,44 +35,16 @@ - - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} - io.apimatic core-interfaces [0.3, 0.4) - - junit - junit - 4.13.2 - test - - - javax.xml.bind - jaxb-api - 2.4.0-b180830.0359 - - - org.glassfish.jaxb - jaxb-runtime - 2.3.2 - - - org.mockito - mockito-core - 4.11.0 - test - - - org.mockito - mockito-inline - 4.11.0 - test - + + com.fasterxml.jackson.core + jackson-databind + ${jackson.databind.version} + com.fasterxml.jackson.core jackson-core @@ -88,17 +60,30 @@ slf4j-api 2.0.10 - - org.jacoco - jacoco-maven-plugin - 0.8.10 - test - - - org.glassfish - javax.json - 1.1.4 - + + junit + junit + 4.13.2 + test + + + org.jacoco + jacoco-maven-plugin + 0.8.10 + test + + + org.mockito + mockito-core + 4.11.0 + test + + + org.mockito + mockito-inline + 4.11.0 + test + diff --git a/src/main/java/io/apimatic/core/ErrorCase.java b/src/main/java/io/apimatic/core/ErrorCase.java index ad514cfe..25d021a7 100644 --- a/src/main/java/io/apimatic/core/ErrorCase.java +++ b/src/main/java/io/apimatic/core/ErrorCase.java @@ -2,10 +2,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.json.Json; -import javax.json.JsonException; -import javax.json.JsonPointer; -import javax.json.JsonStructure; import io.apimatic.core.types.CoreApiException; import io.apimatic.core.utilities.CoreHelper; import io.apimatic.coreinterfaces.http.Context; @@ -139,48 +135,41 @@ private String replaceHeadersFromTemplate(HttpHeaders headers, String reason) { private String replaceBodyFromTemplate(String responseBody, String reason) { StringBuilder formatter = new StringBuilder(reason); - JsonStructure jsonStructure = CoreHelper.createJsonStructure(responseBody); Matcher matcher = Pattern.compile("\\{(.*?)\\}").matcher(reason); while (matcher.find()) { String key = matcher.group(1); String pointerKey = key; - replaceBodyString(responseBody, formatter, jsonStructure, key, pointerKey); + replaceBodyString(responseBody, formatter, key, pointerKey); } return formatter.toString().replace("\"", ""); } private void replaceBodyString(String responseBody, StringBuilder formatter, - JsonStructure jsonStructure, String key, String pointerKey) { + String key, String pointerKey) { if (pointerKey.startsWith("$response.body")) { String formatKey = String.format("{%s}", key); int index = formatter.indexOf(formatKey); - String toReplaceString = ""; - toReplaceString = extractReplacementString(responseBody, jsonStructure, pointerKey, - toReplaceString); if (index != -1) { - try { - - formatter.replace(index, index + formatKey.length(), toReplaceString); - } catch (JsonException ex) { - formatter.replace(index, index + formatKey.length(), ""); - } + String toReplaceString = extractReplacementString(responseBody, pointerKey); + formatter.replace(index, index + formatKey.length(), toReplaceString); } } } - private String extractReplacementString(String responseBody, JsonStructure jsonStructure, - String pointerKey, String toReplaceString) { + private String extractReplacementString(String responseBody, String pointerKey) { if (pointerKey.contains("#")) { pointerKey = pointerKey.replace("$response.body#", ""); - JsonPointer jsonPointer = Json.createPointer(pointerKey); - if (jsonStructure != null && jsonPointer.containsValue(jsonStructure)) { - toReplaceString = jsonPointer.getValue(jsonStructure).toString(); - } - } else { - if (responseBody != null && !responseBody.isEmpty()) { - toReplaceString = responseBody; + String pointerValue = CoreHelper.getValueFromJson(pointerKey, responseBody); + if (pointerValue != null) { + return pointerValue; } + return ""; } - return toReplaceString; + + if (responseBody != null && !responseBody.isEmpty()) { + return responseBody; + } + + return ""; } } diff --git a/src/main/java/io/apimatic/core/utilities/CoreHelper.java b/src/main/java/io/apimatic/core/utilities/CoreHelper.java index fece702d..c989325c 100644 --- a/src/main/java/io/apimatic/core/utilities/CoreHelper.java +++ b/src/main/java/io/apimatic/core/utilities/CoreHelper.java @@ -31,14 +31,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.json.Json; -import javax.json.JsonNumber; -import javax.json.JsonPointer; -import javax.json.JsonReader; -import javax.json.JsonString; -import javax.json.JsonStructure; -import javax.json.JsonValue; -import javax.json.JsonWriter; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; @@ -67,6 +59,10 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + import io.apimatic.core.annotations.TypeCombinator.FormSerialize; import io.apimatic.core.annotations.TypeCombinator.TypeCombinatorCase; import io.apimatic.core.annotations.TypeCombinator.TypeCombinatorStringCase; @@ -1606,24 +1602,6 @@ public static Map getQueryParameters(String queryUrl) { )); } - /** - * Converts a JSON string to a {@link JsonStructure}. - * - * @param json The JSON string. - * @return The parsed {@link JsonStructure}, or null if parsing fails. - */ - public static JsonStructure createJsonStructure(String json) { - JsonReader jsonReader = Json.createReader(new StringReader(json)); - JsonStructure jsonStructure = null; - try { - jsonStructure = jsonReader.read(); - } catch (Exception e) { - // No need to do anything here - } - jsonReader.close(); - return jsonStructure; - } - /** * Resolves a pointer within a JSON response body or headers. * @@ -1658,31 +1636,32 @@ public static String resolveResponsePointer(String pointer, Response response) { * @param json The JSON string. * @return The value as a string, or null if not found or invalid. */ - private static String getValueFromJson(String pointer, String json) { + public static String getValueFromJson(String pointer, String json) { if (pointer == null || json == null) { return null; } - JsonStructure jsonStructure = CoreHelper.createJsonStructure(json); - JsonPointer jsonPointer = Json.createPointer(pointer); - boolean containsValue = false; try { - containsValue = jsonPointer.containsValue(jsonStructure); - } catch (Exception e) { - // Ignore - } + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(json); - if (jsonStructure == null || !containsValue) { - return null; - } + // Jackson's .at() supports JSON Pointer syntax + JsonNode valueNode = root.at(pointer); + + if (valueNode.isMissingNode() || valueNode.isNull()) { + return null; + } - JsonValue value = jsonPointer.getValue(jsonStructure); + if (valueNode.isTextual()) { + return valueNode.asText(); + } - if (value instanceof JsonString) { - return ((JsonString) value).getString(); + // Return JSON representation for non-text values + return valueNode.toString(); + } catch (Exception e) { + // Ignore or log as needed + return null; } - - return value.toString(); } /** @@ -1694,93 +1673,105 @@ private static String getValueFromJson(String pointer, String json) { * @param updater The function to apply to the value at the pointer. * @return The updated object, or the original if any error occurs. */ - public static T updateValueByPointer(T value, String pointer, - UnaryOperator updater) { - if (value == null || "".equals(pointer) || updater == null) { + public static T updateValueByPointer(T value, String pointer, UnaryOperator updater) { + if (value == null || pointer == null || pointer.isEmpty() || updater == null) { return value; } try { - String json = serialize(value); - JsonStructure structure = createJsonStructure(json); - if (structure == null) { - return value; - } + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.valueToTree(value); - JsonPointer jsonPointer = Json.createPointer(pointer); + // Split pointer into parent path and last segment + int lastSlash = pointer.lastIndexOf('/'); + String parentPointer = (lastSlash > 0) ? pointer.substring(0, lastSlash) : ""; + String fieldName = pointer.substring(lastSlash + 1); - if (!jsonPointer.containsValue(structure)) { - structure = jsonPointer.add(structure, JsonValue.NULL); - } - JsonValue oldJsonValue = jsonPointer.getValue(structure); - Object oldValue = toObject(oldJsonValue); - Object newValueRaw = updater.apply(oldValue); - if (newValueRaw == null) { - return value; + JsonNode parentNode = parentPointer.isEmpty() ? root : root.at(parentPointer); + if (parentNode.isMissingNode() || parentNode.isNull()) { + return value; // invalid parent path } - JsonValue newJsonValue = toJsonValue(newValueRaw); - if (newJsonValue == null) { - return value; + boolean updated = false; + if (parentNode.isObject()) { + updated = updateObjectField((ObjectNode) parentNode, fieldName, updater, mapper); + } else if (parentNode.isArray()) { + updated = updateArrayIndex((ArrayNode) parentNode, fieldName, updater, mapper); } - JsonStructure updated = jsonPointer.replace(structure, newJsonValue); - StringWriter writer = new StringWriter(); - try (JsonWriter jsonWriter = Json.createWriter(writer)) { - jsonWriter.write(updated); - } - - String updatedJson = writer.toString(); - return deserialize(updatedJson, new TypeReference() {}); - + return updated ? mapper.convertValue(root, new TypeReference() {}) : value; } catch (Exception e) { return value; } } + + private static boolean updateObjectField( + ObjectNode objectNode, + String fieldName, + UnaryOperator updater, + ObjectMapper mapper + ) { + JsonNode oldNode = objectNode.get(fieldName); + Object oldValue = toObject(oldNode); + Object newValueRaw = updater.apply(oldValue); - /** - * Converts a {@link JsonValue} into a plain Java object. - * - * @param value The JsonValue. - * @return The equivalent Java object. - */ - private static Object toObject(JsonValue value) { - switch (value.getValueType()) { - case STRING: - return ((JsonString) value).getString(); - case NUMBER: - return ((JsonNumber) value).numberValue(); - case TRUE: - return true; - case FALSE: - return false; - default: - return null; - } + if (newValueRaw == null) return false; + JsonNode newJsonNode = toJsonNode(newValueRaw, mapper); + if (newJsonNode == null) return false; + + objectNode.set(fieldName, newJsonNode); + return true; } - /** - * Converts a plain Java object into a {@link JsonValue}. - * - * @param obj The object to convert. - * @return The corresponding JsonValue or null if unsupported. - */ - private static JsonValue toJsonValue(Object obj) { - if (obj instanceof String) { - return Json.createValue((String) obj); - } - if (obj instanceof Integer) { - return Json.createValue((Integer) obj); - } - if (obj instanceof Long) { - return Json.createValue((Long) obj); - } - if (obj instanceof Double) { - return Json.createValue((Double) obj); + private static boolean updateArrayIndex( + ArrayNode arrayNode, + String indexStr, + UnaryOperator updater, + ObjectMapper mapper + ) { + try { + int index = Integer.parseInt(indexStr); + if (index < 0 || index >= arrayNode.size()) { + return false; // invalid index + } + + JsonNode oldNode = arrayNode.get(index); + Object oldValue = toObject(oldNode); + Object newValueRaw = updater.apply(oldValue); + + if (newValueRaw == null) return false; + JsonNode newJsonNode = toJsonNode(newValueRaw, mapper); + if (newJsonNode == null) return false; + + arrayNode.set(index, newJsonNode); + return true; + } catch (NumberFormatException e) { + return false; } - if (obj instanceof Boolean) { - return Boolean.TRUE.equals(obj) ? JsonValue.TRUE : JsonValue.FALSE; + } + + private static Object toObject(JsonNode node) { + if (node == null || node.isNull()) return null; + if (node.isTextual()) return node.asText(); + if (node.isNumber()) return node.numberValue(); + if (node.isBoolean()) return node.booleanValue(); + + return null; + } + + private static JsonNode toJsonNode(Object obj, ObjectMapper mapper) { + if (obj == null) return NullNode.getInstance(); + + if (obj instanceof String || + obj instanceof Integer || + obj instanceof Long || + obj instanceof Double || + obj instanceof Float || + obj instanceof Boolean) { + return mapper.valueToTree(obj); } + + // Reject collections, maps, and arbitrary objects return null; } From 2edabeba7b2714bd248f15d6c938d0f85715251f Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Mon, 18 Aug 2025 09:21:29 +0500 Subject: [PATCH 2/6] adds back the jaxb and xml.bind dependencies for java 8+ --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index b9f01376..d64e1f05 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,16 @@ core-interfaces [0.3, 0.4) + + javax.xml.bind + jaxb-api + 2.4.0-b180830.0359 + + + org.glassfish.jaxb + jaxb-runtime + 2.3.2 + com.fasterxml.jackson.core jackson-databind From 8e47cc614d800c1bbf9289b4349bafbd5828cfc5 Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Mon, 18 Aug 2025 10:20:39 +0500 Subject: [PATCH 3/6] fix: addressed linting issues in CoreHelper --- .../apimatic/core/utilities/CoreHelper.java | 107 ++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/src/main/java/io/apimatic/core/utilities/CoreHelper.java b/src/main/java/io/apimatic/core/utilities/CoreHelper.java index c989325c..c9ae34da 100644 --- a/src/main/java/io/apimatic/core/utilities/CoreHelper.java +++ b/src/main/java/io/apimatic/core/utilities/CoreHelper.java @@ -1673,13 +1673,13 @@ public static String getValueFromJson(String pointer, String json) { * @param updater The function to apply to the value at the pointer. * @return The updated object, or the original if any error occurs. */ - public static T updateValueByPointer(T value, String pointer, UnaryOperator updater) { + public static T updateValueByPointer(T value, String pointer, + UnaryOperator updater) { if (value == null || pointer == null || pointer.isEmpty() || updater == null) { return value; } try { - ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.valueToTree(value); // Split pointer into parent path and last segment @@ -1694,9 +1694,9 @@ public static T updateValueByPointer(T value, String pointer, UnaryOperator< boolean updated = false; if (parentNode.isObject()) { - updated = updateObjectField((ObjectNode) parentNode, fieldName, updater, mapper); + updated = updateObjectField((ObjectNode) parentNode, fieldName, updater); } else if (parentNode.isArray()) { - updated = updateArrayIndex((ArrayNode) parentNode, fieldName, updater, mapper); + updated = updateArrayIndex((ArrayNode) parentNode, fieldName, updater); } return updated ? mapper.convertValue(root, new TypeReference() {}) : value; @@ -1704,70 +1704,87 @@ public static T updateValueByPointer(T value, String pointer, UnaryOperator< return value; } } - - private static boolean updateObjectField( - ObjectNode objectNode, - String fieldName, - UnaryOperator updater, - ObjectMapper mapper - ) { + + private static boolean updateObjectField( ObjectNode objectNode, String fieldName, + UnaryOperator updater) { JsonNode oldNode = objectNode.get(fieldName); Object oldValue = toObject(oldNode); Object newValueRaw = updater.apply(oldValue); - if (newValueRaw == null) return false; - JsonNode newJsonNode = toJsonNode(newValueRaw, mapper); - if (newJsonNode == null) return false; + if (newValueRaw == null) { + return false; + } + JsonNode newJsonNode = toJsonNode(newValueRaw); + if (newJsonNode == null) { + return false; + } objectNode.set(fieldName, newJsonNode); return true; } - private static boolean updateArrayIndex( - ArrayNode arrayNode, - String indexStr, - UnaryOperator updater, - ObjectMapper mapper - ) { + private static boolean updateArrayIndex(ArrayNode arrayNode, String indexStr, + UnaryOperator updater) { + int index = -1; + try { - int index = Integer.parseInt(indexStr); - if (index < 0 || index >= arrayNode.size()) { - return false; // invalid index - } + index = Integer.parseInt(indexStr); + } catch (NumberFormatException e) { + return false; + } - JsonNode oldNode = arrayNode.get(index); - Object oldValue = toObject(oldNode); - Object newValueRaw = updater.apply(oldValue); + if (index < 0 || index >= arrayNode.size()) { + return false; // invalid index + } - if (newValueRaw == null) return false; - JsonNode newJsonNode = toJsonNode(newValueRaw, mapper); - if (newJsonNode == null) return false; + JsonNode oldNode = arrayNode.get(index); + Object oldValue = toObject(oldNode); + Object newValueRaw = updater.apply(oldValue); - arrayNode.set(index, newJsonNode); - return true; - } catch (NumberFormatException e) { + if (newValueRaw == null) { return false; } + + JsonNode newJsonNode = toJsonNode(newValueRaw); + if (newJsonNode == null) { + return false; + } + + arrayNode.set(index, newJsonNode); + return true; } private static Object toObject(JsonNode node) { - if (node == null || node.isNull()) return null; - if (node.isTextual()) return node.asText(); - if (node.isNumber()) return node.numberValue(); - if (node.isBoolean()) return node.booleanValue(); + if (node == null || node.isNull()) { + return null; + } + + if (node.isTextual()) { + return node.asText(); + } + + if (node.isNumber()) { + return node.numberValue(); + } + + if (node.isBoolean()) { + return node.booleanValue(); + } return null; } - private static JsonNode toJsonNode(Object obj, ObjectMapper mapper) { - if (obj == null) return NullNode.getInstance(); + private static JsonNode toJsonNode(Object obj) { + if (obj == null) { + return NullNode.getInstance(); + } - if (obj instanceof String || - obj instanceof Integer || - obj instanceof Long || - obj instanceof Double || - obj instanceof Float || - obj instanceof Boolean) { + if (obj instanceof String + || obj instanceof Integer + || obj instanceof Long + || obj instanceof Double + || obj instanceof Float + || obj instanceof Boolean) { return mapper.valueToTree(obj); } From 837c05a7d5f338503192945255b6a587bfec1a8c Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Mon, 18 Aug 2025 10:27:04 +0500 Subject: [PATCH 4/6] fix: addressed linting issues in getValueByJson --- src/main/java/io/apimatic/core/utilities/CoreHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/io/apimatic/core/utilities/CoreHelper.java b/src/main/java/io/apimatic/core/utilities/CoreHelper.java index c9ae34da..1bfc7a6a 100644 --- a/src/main/java/io/apimatic/core/utilities/CoreHelper.java +++ b/src/main/java/io/apimatic/core/utilities/CoreHelper.java @@ -1642,7 +1642,6 @@ public static String getValueFromJson(String pointer, String json) { } try { - ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(json); // Jackson's .at() supports JSON Pointer syntax @@ -1705,7 +1704,7 @@ public static T updateValueByPointer(T value, String pointer, } } - private static boolean updateObjectField( ObjectNode objectNode, String fieldName, + private static boolean updateObjectField(ObjectNode objectNode, String fieldName, UnaryOperator updater) { JsonNode oldNode = objectNode.get(fieldName); Object oldValue = toObject(oldNode); From 87dac6ab434e12bb3e02d448ba04decb652f40ed Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Tue, 19 Aug 2025 15:53:38 +0500 Subject: [PATCH 5/6] fix: removed jaxb runtime dependency --- .gitignore | 1 + pom.xml | 15 +++++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 0621be2d..d98671b0 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ Thumbs.db *.project .settings site +.vscode/ diff --git a/pom.xml b/pom.xml index d64e1f05..f1a83efd 100644 --- a/pom.xml +++ b/pom.xml @@ -40,16 +40,11 @@ core-interfaces [0.3, 0.4) - - javax.xml.bind - jaxb-api - 2.4.0-b180830.0359 - - - org.glassfish.jaxb - jaxb-runtime - 2.3.2 - + + javax.xml.bind + jaxb-api + 2.4.0-b180830.0359 + com.fasterxml.jackson.core jackson-databind From a8d0ea3c78ec6ed24af787aecd033d505efe4825 Mon Sep 17 00:00:00 2001 From: Asad Ali <14asadali@gmail.com> Date: Tue, 19 Aug 2025 15:57:35 +0500 Subject: [PATCH 6/6] Revert "fix: removed jaxb runtime dependency" This reverts commit 87dac6ab434e12bb3e02d448ba04decb652f40ed. --- .gitignore | 1 - pom.xml | 15 ++++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index d98671b0..0621be2d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,3 @@ Thumbs.db *.project .settings site -.vscode/ diff --git a/pom.xml b/pom.xml index f1a83efd..d64e1f05 100644 --- a/pom.xml +++ b/pom.xml @@ -40,11 +40,16 @@ core-interfaces [0.3, 0.4) - - javax.xml.bind - jaxb-api - 2.4.0-b180830.0359 - + + javax.xml.bind + jaxb-api + 2.4.0-b180830.0359 + + + org.glassfish.jaxb + jaxb-runtime + 2.3.2 + com.fasterxml.jackson.core jackson-databind