diff --git a/src/main/java/com/crowdin/client/core/http/exceptions/HttpBatchBadRequestException.java b/src/main/java/com/crowdin/client/core/http/exceptions/HttpBatchBadRequestException.java new file mode 100644 index 000000000..d46d1d0a6 --- /dev/null +++ b/src/main/java/com/crowdin/client/core/http/exceptions/HttpBatchBadRequestException.java @@ -0,0 +1,42 @@ +package com.crowdin.client.core.http.exceptions; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class HttpBatchBadRequestException extends CrowdinApiException{ + private final List errors; + + public HttpBatchBadRequestException() { + this.errors = Collections.emptyList(); + } + + @Data + public static class BatchErrors implements Serializable { + private Integer index; + private List errors; + + } + + @Data + public static class ErrorHolder { + private ErrorKey error; + } + + @Data + public static class ErrorKey implements Serializable { + private String key; + private List errors; + } + + @Data + public static class Error { + private String code; + private String message; + } +} diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializer.java b/src/main/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializer.java index e0a722948..ae28af5ca 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializer.java @@ -2,6 +2,7 @@ import com.crowdin.client.core.http.exceptions.CrowdinApiException; import com.crowdin.client.core.http.exceptions.HttpBadRequestException; +import com.crowdin.client.core.http.exceptions.HttpBatchBadRequestException; import com.crowdin.client.core.http.exceptions.HttpException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.TreeNode; @@ -10,9 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; public class CrowdinApiExceptionDeserializer extends JsonDeserializer { @@ -25,14 +23,18 @@ public CrowdinApiExceptionDeserializer(ObjectMapper objectMapper) { @Override public CrowdinApiException deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { TreeNode treeNode = p.getCodec().readTree(p); - Iterable iterable = treeNode::fieldNames; - List fields = StreamSupport - .stream(iterable.spliterator(), false) - .collect(Collectors.toList()); - if (fields.contains("errors")) { - return this.objectMapper.readValue(treeNode.toString(), HttpBadRequestException.class); - } else if (fields.contains("error")) { - return this.objectMapper.readValue(treeNode.toString(), HttpException.class); + TreeNode errors = treeNode.get("errors"); + + if (errors != null) { + TreeNode firstElement = errors.get(0); + + if (firstElement != null && firstElement.get("index") != null) { + return this.objectMapper.treeToValue(treeNode, HttpBatchBadRequestException.class); + } + + return this.objectMapper.treeToValue(treeNode, HttpBadRequestException.class); + } else if (treeNode.get("error") != null) { + return this.objectMapper.treeToValue(treeNode, HttpException.class); } else { return HttpException.fromMessage(treeNode.toString()); } diff --git a/src/test/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializerTest.java b/src/test/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializerTest.java index 7f341ed91..0e053f7f8 100644 --- a/src/test/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializerTest.java +++ b/src/test/java/com/crowdin/client/core/http/impl/json/CrowdinApiExceptionDeserializerTest.java @@ -2,6 +2,7 @@ import com.crowdin.client.core.http.exceptions.CrowdinApiException; import com.crowdin.client.core.http.exceptions.HttpBadRequestException; +import com.crowdin.client.core.http.exceptions.HttpBatchBadRequestException; import com.crowdin.client.core.http.exceptions.HttpException; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; @@ -21,16 +22,19 @@ public class CrowdinApiExceptionDeserializerTest { private String error; private String errorsResponse; + private String batchErrorsResponse; private String unrecognizedError; @BeforeEach void setUp() throws IOException { String resourceDir = "api/core/error.json"; String errorResponseDir = "api/core/errorsResponse.json"; + String batchErrorsResponseDir = "api/core/batchErrorsResponse.json"; String unrecognizedErrorDir = "api/core/unrecognizedError.json"; error = getFile(resourceDir); errorsResponse = getFile(errorResponseDir); + batchErrorsResponse = getFile(batchErrorsResponseDir); unrecognizedError = getFile(unrecognizedErrorDir); } @@ -48,6 +52,10 @@ private String getFile(String resourcePath) throws IOException { void testDeserializeHttpBadRequestException() throws IOException { testDeserialize(errorsResponse, HttpBadRequestException.class); } + @Test + void testDeserializeHttpBatchBadRequestException() throws IOException { + testDeserialize(batchErrorsResponse, HttpBatchBadRequestException.class); + } @Test void testDeserializeHttpException() throws IOException { diff --git a/src/test/java/com/crowdin/client/sourcestrings/SourceStringsApiTest.java b/src/test/java/com/crowdin/client/sourcestrings/SourceStringsApiTest.java index e1db9c1e0..da34c67f7 100644 --- a/src/test/java/com/crowdin/client/sourcestrings/SourceStringsApiTest.java +++ b/src/test/java/com/crowdin/client/sourcestrings/SourceStringsApiTest.java @@ -1,5 +1,6 @@ package com.crowdin.client.sourcestrings; +import com.crowdin.client.core.http.exceptions.HttpBatchBadRequestException; import com.crowdin.client.core.model.PatchOperation; import com.crowdin.client.core.model.PatchRequest; import com.crowdin.client.core.model.ResponseList; diff --git a/src/test/resources/api/core/batchErrorsResponse.json b/src/test/resources/api/core/batchErrorsResponse.json new file mode 100644 index 000000000..912a2802b --- /dev/null +++ b/src/test/resources/api/core/batchErrorsResponse.json @@ -0,0 +1,36 @@ +{ + "errors": [ + { + "index": 0, + "errors": [ + { + "error": { + "key": "identifier", + "errors": [ + { + "code": "notUnique", + "message": "Invalid identifier given. Identifier must be unique" + } + ] + } + } + ] + }, + { + "index": 2, + "errors": [ + { + "error": { + "key": "identifier", + "errors": [ + { + "code": "notUnique", + "message": "Invalid identifier given. Identifier must be unique" + } + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/src/test/resources/api/strings/stringBatchOperationsErrorRequest.json b/src/test/resources/api/strings/stringBatchOperationsErrorRequest.json new file mode 100644 index 000000000..466e5122c --- /dev/null +++ b/src/test/resources/api/strings/stringBatchOperationsErrorRequest.json @@ -0,0 +1,28 @@ +[ + { + "op": "add", + "path": "/-", + "value": { + "text": "new added string", + "identifier": "a.b.c", + "context": "context for new string", + "fileId": 5, + "isHidden": false + } + }, + { + "op": "remove", + "path": "/2815" + }, + { + "op": "add", + "path": "/-", + "value": { + "text": "new added string", + "identifier": "a.b.c", + "context": "context for new string", + "fileId": 5, + "isHidden": false + } + } +] \ No newline at end of file