From 67386ac60227df3f006b441eac80a62cbdf59986 Mon Sep 17 00:00:00 2001 From: "maksim.safronov" Date: Mon, 12 Aug 2024 15:59:18 +0400 Subject: [PATCH 1/7] ECWID-144513 startersite error Caused by IllegalStateException: Expected but was STRING at line column path at JsonReader.beginObject(JsonReader.java:) --- src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index 225807055..d31dce1f2 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -15,6 +15,7 @@ import com.ecwid.apiclient.v3.impl.* import com.ecwid.apiclient.v3.jsontransformer.JsonTransformer import com.ecwid.apiclient.v3.jsontransformer.JsonTransformerProvider import com.ecwid.apiclient.v3.jsontransformer.PolymorphicType +import com.ecwid.apiclient.v3.jsontransformer.gson.GsonTransformer import com.ecwid.apiclient.v3.metric.RequestSizeMetric import com.ecwid.apiclient.v3.metric.RequestTimeMetric import com.ecwid.apiclient.v3.metric.ResponseSizeMetric @@ -23,6 +24,7 @@ import com.ecwid.apiclient.v3.responsefields.responseFieldsOf import com.ecwid.apiclient.v3.util.buildEndpointPath import com.ecwid.apiclient.v3.util.createSecurePatterns import com.ecwid.apiclient.v3.util.maskLogString +import com.google.gson.Gson import java.net.URI import java.util.* import java.util.logging.Level @@ -196,7 +198,8 @@ class ApiClientHelper private constructor( try { val responseBody = responseBytes.asString() logErrorResponseIfNeeded(requestId, requestTime, httpResponse.statusCode, responseBody) - val ecwidError = if (responseBody.isNotBlank()) { + // Because of a html-based balancer error we must check responseBody string to be an actual json object + val ecwidError = if (responseBody.isNotBlank() && responseBody.startsWith("{")) { jsonTransformer.deserialize(responseBody, EcwidApiError::class.java) } else { null From 79e163d00020e87490368cab0b3dd595e464cb0e Mon Sep 17 00:00:00 2001 From: "maksim.safronov" Date: Mon, 12 Aug 2024 16:01:58 +0400 Subject: [PATCH 2/7] ECWID-144513 startersite error Caused by IllegalStateException: Expected but was STRING at line column path at JsonReader.beginObject(JsonReader.java:) - removed unused imports --- src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index d31dce1f2..a6b32c9c8 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -15,7 +15,6 @@ import com.ecwid.apiclient.v3.impl.* import com.ecwid.apiclient.v3.jsontransformer.JsonTransformer import com.ecwid.apiclient.v3.jsontransformer.JsonTransformerProvider import com.ecwid.apiclient.v3.jsontransformer.PolymorphicType -import com.ecwid.apiclient.v3.jsontransformer.gson.GsonTransformer import com.ecwid.apiclient.v3.metric.RequestSizeMetric import com.ecwid.apiclient.v3.metric.RequestTimeMetric import com.ecwid.apiclient.v3.metric.ResponseSizeMetric @@ -24,7 +23,6 @@ import com.ecwid.apiclient.v3.responsefields.responseFieldsOf import com.ecwid.apiclient.v3.util.buildEndpointPath import com.ecwid.apiclient.v3.util.createSecurePatterns import com.ecwid.apiclient.v3.util.maskLogString -import com.google.gson.Gson import java.net.URI import java.util.* import java.util.logging.Level From 73e3256015e13b75afb5b40e1f73e5b6f3027de6 Mon Sep 17 00:00:00 2001 From: "maksim.safronov" Date: Tue, 13 Aug 2024 11:00:14 +0400 Subject: [PATCH 3/7] ECWID-144513 startersite error Caused by IllegalStateException: Expected but was STRING at line column path at JsonReader.beginObject(JsonReader.java:) - reword --- src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index a6b32c9c8..1ed0f95de 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -196,7 +196,7 @@ class ApiClientHelper private constructor( try { val responseBody = responseBytes.asString() logErrorResponseIfNeeded(requestId, requestTime, httpResponse.statusCode, responseBody) - // Because of a html-based balancer error we must check responseBody string to be an actual json object + // Because of a html-based balancer error we should check responseBody string to be an actual json object val ecwidError = if (responseBody.isNotBlank() && responseBody.startsWith("{")) { jsonTransformer.deserialize(responseBody, EcwidApiError::class.java) } else { From 4dee2dec00a65f5a0660dbed80f768600b268d7e Mon Sep 17 00:00:00 2001 From: "maksim.safronov" Date: Tue, 27 Aug 2024 14:27:15 +0400 Subject: [PATCH 4/7] ECWID-144513 new eager responseBody isJsonObject check --- .../com/ecwid/apiclient/v3/ApiClientHelper.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index 1ed0f95de..ac562cd82 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -23,6 +23,9 @@ import com.ecwid.apiclient.v3.responsefields.responseFieldsOf import com.ecwid.apiclient.v3.util.buildEndpointPath import com.ecwid.apiclient.v3.util.createSecurePatterns import com.ecwid.apiclient.v3.util.maskLogString +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.google.gson.JsonSyntaxException import java.net.URI import java.util.* import java.util.logging.Level @@ -197,7 +200,7 @@ class ApiClientHelper private constructor( val responseBody = responseBytes.asString() logErrorResponseIfNeeded(requestId, requestTime, httpResponse.statusCode, responseBody) // Because of a html-based balancer error we should check responseBody string to be an actual json object - val ecwidError = if (responseBody.isNotBlank() && responseBody.startsWith("{")) { + val ecwidError = if (responseBody.isNotBlank() && isJsonObject(responseBody)) { jsonTransformer.deserialize(responseBody, EcwidApiError::class.java) } else { null @@ -554,3 +557,11 @@ private fun createAdditionalDataPolymorphicType(): PolymorphicType Date: Tue, 27 Aug 2024 17:01:44 +0400 Subject: [PATCH 5/7] ECWID-144513 detekt fix --- src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index ac562cd82..d0181f65b 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -23,7 +23,6 @@ import com.ecwid.apiclient.v3.responsefields.responseFieldsOf import com.ecwid.apiclient.v3.util.buildEndpointPath import com.ecwid.apiclient.v3.util.createSecurePatterns import com.ecwid.apiclient.v3.util.maskLogString -import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.JsonSyntaxException import java.net.URI From 4ef36ef2a43e92df565e0d7e781b9219e51528c8 Mon Sep 17 00:00:00 2001 From: "maksim.safronov" Date: Wed, 28 Aug 2024 10:25:47 +0400 Subject: [PATCH 6/7] ECWID-144513 isJsonObject null-safety with unit-tests --- .../com/ecwid/apiclient/v3/ApiClientHelper.kt | 6 ++-- .../apiclient/v3/ApiClientHelperUnitTest.kt | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/com/ecwid/apiclient/v3/ApiClientHelperUnitTest.kt diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index d0181f65b..708e3884e 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -557,10 +557,10 @@ private fun createAdditionalDataPolymorphicType(): PolymorphicType Date: Fri, 20 Sep 2024 10:36:00 +0400 Subject: [PATCH 7/7] ECWID-144513 safe deserializeOrNull implementation --- .../com/ecwid/apiclient/v3/ApiClientHelper.kt | 15 ++-------- .../v3/jsontransformer/JsonTransformer.kt | 3 +- .../jsontransformer/gson/GsonTransformer.kt | 10 ++++++- .../apiclient/v3/ApiClientHelperUnitTest.kt | 28 ------------------- .../gson/GsonTransformerTest.kt | 7 +++++ 5 files changed, 20 insertions(+), 43 deletions(-) delete mode 100644 src/test/kotlin/com/ecwid/apiclient/v3/ApiClientHelperUnitTest.kt diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt index 708e3884e..fa6a7e7b4 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/ApiClientHelper.kt @@ -23,8 +23,6 @@ import com.ecwid.apiclient.v3.responsefields.responseFieldsOf import com.ecwid.apiclient.v3.util.buildEndpointPath import com.ecwid.apiclient.v3.util.createSecurePatterns import com.ecwid.apiclient.v3.util.maskLogString -import com.google.gson.JsonParser -import com.google.gson.JsonSyntaxException import java.net.URI import java.util.* import java.util.logging.Level @@ -198,9 +196,8 @@ class ApiClientHelper private constructor( try { val responseBody = responseBytes.asString() logErrorResponseIfNeeded(requestId, requestTime, httpResponse.statusCode, responseBody) - // Because of a html-based balancer error we should check responseBody string to be an actual json object - val ecwidError = if (responseBody.isNotBlank() && isJsonObject(responseBody)) { - jsonTransformer.deserialize(responseBody, EcwidApiError::class.java) + val ecwidError = if (responseBody.isNotBlank()) { + jsonTransformer.deserializeOrNull(responseBody, EcwidApiError::class.java) } else { null } @@ -556,11 +553,3 @@ private fun createAdditionalDataPolymorphicType(): PolymorphicType deserialize(json: String, clazz: Class): V? + fun deserialize(json: String, clazz: Class): V + fun deserializeOrNull(json: String, clazz: Class): V? } diff --git a/src/main/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformer.kt b/src/main/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformer.kt index ddb5532e9..2d3dcef08 100644 --- a/src/main/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformer.kt +++ b/src/main/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformer.kt @@ -36,13 +36,21 @@ class GsonTransformer(polymorphicTypes: List>) : JsonTransfor } } - override fun deserialize(json: String, clazz: Class): V? { + override fun deserialize(json: String, clazz: Class): V { try { return gson.fromJson(json, clazz) } catch (e: JsonParseException) { throw JsonDeserializationException(e.message, e) } } + + override fun deserializeOrNull(json: String, clazz: Class): V? { + return try { + return gson.fromJson(json, clazz) + } catch (e: JsonParseException) { + null + } + } } private fun JsonObject.mergeJsonObject(from: JsonObject) { diff --git a/src/test/kotlin/com/ecwid/apiclient/v3/ApiClientHelperUnitTest.kt b/src/test/kotlin/com/ecwid/apiclient/v3/ApiClientHelperUnitTest.kt deleted file mode 100644 index 201b76343..000000000 --- a/src/test/kotlin/com/ecwid/apiclient/v3/ApiClientHelperUnitTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.ecwid.apiclient.v3 - -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class ApiClientHelperUnitTest { - - @Test - fun `should return true if input string is valid json`() { - val testString = "{\"foo\":\"bar\"}" - assertTrue { isJsonObject(testString) } - } - - @ParameterizedTest - @ValueSource(strings = ["some sample text", "\"foo\":\"bar\"}", ""]) - fun `should return false if input string is not json`(input: String) { - assertFalse { isJsonObject(input) } - } - - @Test - fun `should return false if input string is null`() { - val testString = null - assertFalse { isJsonObject(testString) } - } -} diff --git a/src/test/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformerTest.kt b/src/test/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformerTest.kt index aa395e59f..780d29497 100644 --- a/src/test/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformerTest.kt +++ b/src/test/kotlin/com/ecwid/apiclient/v3/jsontransformer/gson/GsonTransformerTest.kt @@ -230,6 +230,13 @@ internal class GsonTransformerTest { ) } + @Test + fun `deserializeOrNull of broken ParsedResponseWithExt`() { + val json = "'testField': {'baseField': 'base', 'extField': 'ext'}}" + val deserializedValue = transformer.deserializeOrNull(json, TestParsedResponseWithExt::class.java) + assertEquals(null, deserializedValue) + } + } private fun assertJsonEquals(expected: String, actual: String) {