From a1aba43b990796ebffa6955cb1cfaa1cd2c5343d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ianar=C3=A9=20S=C3=A9vi?= Date: Tue, 7 Apr 2026 13:41:13 +0200 Subject: [PATCH 1/3] :recycle: :boom: LocalResponse class should be version-specific --- .../java/com/mindee/input/LocalResponse.java | 28 +------ .../com/mindee/v1/input/LocalResponse.java | 83 +++++++++++++++++++ .../com/mindee/v2/input/LocalResponse.java | 52 ++++++++++++ .../java/com/mindee/v1/MindeeClientTest.java | 2 +- .../input/LocalResponseTest.java} | 23 +++-- .../java/com/mindee/v2/MindeeClientTest.java | 2 +- .../input/LocalResponseTest.java} | 17 ++-- .../java/com/mindee/v2/parsing/JobTest.java | 2 +- .../mindee/v2/product/ClassificationTest.java | 2 +- .../java/com/mindee/v2/product/CropTest.java | 2 +- .../{parsing => product}/ExtractionTest.java | 4 +- .../java/com/mindee/v2/product/OcrTest.java | 2 +- .../java/com/mindee/v2/product/SplitTest.java | 2 +- 13 files changed, 170 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/mindee/v1/input/LocalResponse.java create mode 100644 src/main/java/com/mindee/v2/input/LocalResponse.java rename src/test/java/com/mindee/{input/LocalResponseV1Test.java => v1/input/LocalResponseTest.java} (68%) rename src/test/java/com/mindee/{input/LocalResponseV2Test.java => v2/input/LocalResponseTest.java} (75%) rename src/test/java/com/mindee/v2/{parsing => product}/ExtractionTest.java (99%) diff --git a/src/main/java/com/mindee/input/LocalResponse.java b/src/main/java/com/mindee/input/LocalResponse.java index 3eabd1423..736006c13 100644 --- a/src/main/java/com/mindee/input/LocalResponse.java +++ b/src/main/java/com/mindee/input/LocalResponse.java @@ -1,8 +1,5 @@ package com.mindee.input; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.mindee.MindeeException; -import com.mindee.v2.parsing.CommonResponse; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -24,9 +21,8 @@ * A Mindee response saved locally. */ @Getter -public class LocalResponse { - private final byte[] file; - private static final ObjectMapper mapper = new ObjectMapper(); +public abstract class LocalResponse { + protected final byte[] file; /** * Load from an {@link InputStream}. @@ -106,24 +102,4 @@ public String getHmacSignature(String secretKey) { public boolean isValidHmacSignature(String secretKey, String signature) { return signature.equals(getHmacSignature(secretKey)); } - - /** - * Deserialize this local JSON payload into a specific {@link CommonResponse} - * subtype: {@code InferenceResponse}, {@code JobResponse}. - * - * @param responseClass the concrete class to instantiate - * @param generic {@link CommonResponse} - * @return Either a {@code InferenceResponse} or {@code JobResponse} instance. - * @throws MindeeException if the payload cannot be deserialized into the requested type - */ - public T deserializeResponse(Class responseClass) { - ObjectMapper mapper = new ObjectMapper(); - try { - T response = mapper.readValue(this.file, responseClass); - response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); - return response; - } catch (Exception ex) { - throw new MindeeException("Invalid class specified for deserialization.", ex); - } - } } diff --git a/src/main/java/com/mindee/v1/input/LocalResponse.java b/src/main/java/com/mindee/v1/input/LocalResponse.java new file mode 100644 index 000000000..1791e2aeb --- /dev/null +++ b/src/main/java/com/mindee/v1/input/LocalResponse.java @@ -0,0 +1,83 @@ +package com.mindee.v1.input; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mindee.MindeeException; +import com.mindee.v1.parsing.common.AsyncPredictResponse; +import com.mindee.v1.parsing.common.Inference; +import com.mindee.v1.parsing.common.PredictResponse; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +/** + * A Mindee response saved locally. + */ +public class LocalResponse extends com.mindee.input.LocalResponse { + + public LocalResponse(InputStream input) { + super(input); + } + + public LocalResponse(String input) { + super(input); + } + + public LocalResponse(File input) throws IOException { + super(input); + } + + public LocalResponse(Path input) throws IOException { + super(input); + } + + /** + * Deserialize this local JSON payload into a specific {@link AsyncPredictResponse}. + * subtype: {@code InferenceResponse}, {@code JobResponse}. + * + * @param responseClass the concrete class to instantiate + * @param generic {@link Inference} + * @return A {@link AsyncPredictResponse} instance. + * @throws MindeeException if the payload cannot be deserialized into the requested type + */ + public AsyncPredictResponse deserializeAsyncResponse( + Class responseClass + ) { + var objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + var type = objectMapper + .getTypeFactory() + .constructParametricType(AsyncPredictResponse.class, responseClass); + try { + AsyncPredictResponse response = objectMapper.readValue(this.file, type); + response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); + return response; + } catch (Exception ex) { + throw new MindeeException("Invalid class specified for deserialization.", ex); + } + } + + /** + * Deserialize this local JSON payload into a specific {@link PredictResponse}. + * + * @param responseClass the concrete class to instantiate + * @param generic {@link Inference} + * @return A {@link PredictResponse} instance. + * @throws MindeeException if the payload cannot be deserialized into the requested type + */ + public PredictResponse deserializeSyncResponse(Class responseClass) { + var objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + var type = objectMapper + .getTypeFactory() + .constructParametricType(PredictResponse.class, responseClass); + try { + PredictResponse response = objectMapper.readValue(this.file, type); + response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); + return response; + } catch (Exception ex) { + throw new MindeeException("Invalid class specified for deserialization.", ex); + } + } +} diff --git a/src/main/java/com/mindee/v2/input/LocalResponse.java b/src/main/java/com/mindee/v2/input/LocalResponse.java new file mode 100644 index 000000000..d06c373e9 --- /dev/null +++ b/src/main/java/com/mindee/v2/input/LocalResponse.java @@ -0,0 +1,52 @@ +package com.mindee.v2.input; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mindee.MindeeException; +import com.mindee.v2.parsing.CommonResponse; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +/** + * A Mindee response saved locally. + */ +public class LocalResponse extends com.mindee.input.LocalResponse { + + public LocalResponse(InputStream input) { + super(input); + } + + public LocalResponse(String input) { + super(input); + } + + public LocalResponse(File input) throws IOException { + super(input); + } + + public LocalResponse(Path input) throws IOException { + super(input); + } + + /** + * Deserialize this local JSON payload into a specific {@link CommonResponse} + * subtype: {@code InferenceResponse}, {@code JobResponse}. + * + * @param responseClass the concrete class to instantiate + * @param generic {@link CommonResponse} + * @return Either a {@code InferenceResponse} or {@code JobResponse} instance. + * @throws MindeeException if the payload cannot be deserialized into the requested type + */ + public T deserializeResponse(Class responseClass) { + var mapper = new ObjectMapper(); + try { + var response = mapper.readValue(this.file, responseClass); + response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); + return response; + } catch (Exception ex) { + throw new MindeeException("Invalid class specified for deserialization.", ex); + } + } +} diff --git a/src/test/java/com/mindee/v1/MindeeClientTest.java b/src/test/java/com/mindee/v1/MindeeClientTest.java index 4bf21570c..dceae5b4f 100644 --- a/src/test/java/com/mindee/v1/MindeeClientTest.java +++ b/src/test/java/com/mindee/v1/MindeeClientTest.java @@ -5,10 +5,10 @@ import static com.mindee.TestingUtilities.getV1ResourcePathString; import com.mindee.input.LocalInputSource; -import com.mindee.input.LocalResponse; import com.mindee.input.PageOptions; import com.mindee.input.PageOptionsOperation; import com.mindee.v1.clientOptions.PredictOptions; +import com.mindee.v1.input.LocalResponse; import com.mindee.v1.parsing.common.AsyncPredictResponse; import com.mindee.v1.parsing.common.Document; import com.mindee.v1.parsing.common.Job; diff --git a/src/test/java/com/mindee/input/LocalResponseV1Test.java b/src/test/java/com/mindee/v1/input/LocalResponseTest.java similarity index 68% rename from src/test/java/com/mindee/input/LocalResponseV1Test.java rename to src/test/java/com/mindee/v1/input/LocalResponseTest.java index cef89b839..5fd6bc8b3 100644 --- a/src/test/java/com/mindee/input/LocalResponseV1Test.java +++ b/src/test/java/com/mindee/v1/input/LocalResponseTest.java @@ -1,7 +1,8 @@ -package com.mindee.input; +package com.mindee.v1.input; import static com.mindee.TestingUtilities.getV1ResourcePath; +import com.mindee.v1.product.internationalid.InternationalIdV2; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -9,25 +10,25 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class LocalResponseV1Test { +public class LocalResponseTest { /** * Fake secret key. */ String secretKey = "ogNjY44MhvKPGTtVsI8zG82JqWQa68woYQH"; /** - * Real signature using fake secret key. + * Real signature using a fake secret key. */ String signature = "5ed1673e34421217a5dbfcad905ee62261a3dd66c442f3edd19302072bbf70d0"; /** - * File which the signature applies to. + * File that the signature applies to. */ Path filePath = getV1ResourcePath("async/get_completed_empty.json"); @Test void loadDocument_withFile_mustReturnValidLocalResponse() throws IOException { - LocalResponse localResponse = new LocalResponse(new File(this.filePath.toString())); + var localResponse = new LocalResponse(new File(this.filePath.toString())); Assertions.assertNotNull(localResponse.getFile()); Assertions .assertFalse( @@ -35,11 +36,15 @@ void loadDocument_withFile_mustReturnValidLocalResponse() throws IOException { ); Assertions.assertEquals(this.signature, localResponse.getHmacSignature(this.secretKey)); Assertions.assertTrue(localResponse.isValidHmacSignature(this.secretKey, this.signature)); + + var response = localResponse.deserializeAsyncResponse(InternationalIdV2.class); + Assertions.assertNotNull(response); + Assertions.assertNotNull(response.getDocumentObj()); } @Test void loadDocument_withString_mustReturnValidLocalResponse() { - LocalResponse localResponse = new LocalResponse("{'some': 'json', 'with': 'data'}"); + var localResponse = new LocalResponse("{'some': 'json', 'with': 'data'}"); Assertions.assertNotNull(localResponse.getFile()); Assertions .assertFalse( @@ -49,7 +54,7 @@ void loadDocument_withString_mustReturnValidLocalResponse() { @Test void loadDocument_withInputStream_mustReturnValidLocalResponse() throws IOException { - LocalResponse localResponse = new LocalResponse(Files.newInputStream(this.filePath)); + var localResponse = new LocalResponse(Files.newInputStream(this.filePath)); Assertions.assertNotNull(localResponse.getFile()); Assertions .assertFalse( @@ -57,5 +62,9 @@ void loadDocument_withInputStream_mustReturnValidLocalResponse() throws IOExcept ); Assertions.assertEquals(this.signature, localResponse.getHmacSignature(this.secretKey)); Assertions.assertTrue(localResponse.isValidHmacSignature(this.secretKey, this.signature)); + + var response = localResponse.deserializeAsyncResponse(InternationalIdV2.class); + Assertions.assertNotNull(response); + Assertions.assertNotNull(response.getDocumentObj()); } } diff --git a/src/test/java/com/mindee/v2/MindeeClientTest.java b/src/test/java/com/mindee/v2/MindeeClientTest.java index 0696fde08..32bc0ade4 100644 --- a/src/test/java/com/mindee/v2/MindeeClientTest.java +++ b/src/test/java/com/mindee/v2/MindeeClientTest.java @@ -7,10 +7,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.input.LocalInputSource; -import com.mindee.input.LocalResponse; import com.mindee.input.URLInputSource; import com.mindee.v2.clientOptions.BaseParameters; import com.mindee.v2.http.MindeeApiV2; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.parsing.CommonResponse; import com.mindee.v2.parsing.JobResponse; import com.mindee.v2.product.extraction.ExtractionResponse; diff --git a/src/test/java/com/mindee/input/LocalResponseV2Test.java b/src/test/java/com/mindee/v2/input/LocalResponseTest.java similarity index 75% rename from src/test/java/com/mindee/input/LocalResponseV2Test.java rename to src/test/java/com/mindee/v2/input/LocalResponseTest.java index 5213d31aa..f898f94a6 100644 --- a/src/test/java/com/mindee/input/LocalResponseV2Test.java +++ b/src/test/java/com/mindee/v2/input/LocalResponseTest.java @@ -1,4 +1,4 @@ -package com.mindee.input; +package com.mindee.v2.input; import static com.mindee.TestingUtilities.getV2ResourcePath; @@ -10,19 +10,19 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class LocalResponseV2Test { +public class LocalResponseTest { /** * Fake secret key. */ String secretKey = "ogNjY44MhvKPGTtVsI8zG82JqWQa68woYQH"; /** - * Real signature using fake secret key. + * Real signature using a fake secret key. */ String signature = "e51bdf80f1a08ed44ee161100fc30a25cb35b4ede671b0a575dc9064a3f5dbf1"; /** - * File which the signature applies to. + * File that the signature applies to. */ Path filePath = getV2ResourcePath("products/extraction/standard_field_types.json"); @@ -34,20 +34,19 @@ protected void assertLocalResponse(LocalResponse localResponse) { ); Assertions.assertEquals(this.signature, localResponse.getHmacSignature(this.secretKey)); Assertions.assertTrue(localResponse.isValidHmacSignature(this.secretKey, this.signature)); - ExtractionResponse response = localResponse.deserializeResponse(ExtractionResponse.class); + var response = localResponse.deserializeResponse(ExtractionResponse.class); Assertions.assertNotNull(response); Assertions.assertNotNull(response.getInference()); } @Test void loadDocument_withFile_mustReturnValidLocalResponse() throws IOException { - LocalResponse localResponse = new LocalResponse(new File(this.filePath.toString())); - assertLocalResponse(localResponse); + assertLocalResponse(new LocalResponse(new File(this.filePath.toString()))); } @Test void loadDocument_withString_mustReturnValidLocalResponse() { - LocalResponse localResponse = new LocalResponse("{'some': 'json', 'with': 'data'}"); + var localResponse = new LocalResponse("{'some': 'json', 'with': 'data'}"); Assertions.assertNotNull(localResponse.getFile()); Assertions .assertFalse( @@ -57,7 +56,7 @@ void loadDocument_withString_mustReturnValidLocalResponse() { @Test void loadDocument_withInputStream_mustReturnValidLocalResponse() throws IOException { - LocalResponse localResponse = new LocalResponse(Files.newInputStream(this.filePath)); + var localResponse = new LocalResponse(Files.newInputStream(this.filePath)); assertLocalResponse(localResponse); } } diff --git a/src/test/java/com/mindee/v2/parsing/JobTest.java b/src/test/java/com/mindee/v2/parsing/JobTest.java index 87f27fd26..71951ceca 100644 --- a/src/test/java/com/mindee/v2/parsing/JobTest.java +++ b/src/test/java/com/mindee/v2/parsing/JobTest.java @@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/src/test/java/com/mindee/v2/product/ClassificationTest.java b/src/test/java/com/mindee/v2/product/ClassificationTest.java index d7701c82c..b457eff43 100644 --- a/src/test/java/com/mindee/v2/product/ClassificationTest.java +++ b/src/test/java/com/mindee/v2/product/ClassificationTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.product.classification.ClassificationResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/product/CropTest.java b/src/test/java/com/mindee/v2/product/CropTest.java index b171a1653..9fbedbad1 100644 --- a/src/test/java/com/mindee/v2/product/CropTest.java +++ b/src/test/java/com/mindee/v2/product/CropTest.java @@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.product.crop.CropResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/parsing/ExtractionTest.java b/src/test/java/com/mindee/v2/product/ExtractionTest.java similarity index 99% rename from src/test/java/com/mindee/v2/parsing/ExtractionTest.java rename to src/test/java/com/mindee/v2/product/ExtractionTest.java index 9927d20aa..6d1e790bf 100644 --- a/src/test/java/com/mindee/v2/parsing/ExtractionTest.java +++ b/src/test/java/com/mindee/v2/product/ExtractionTest.java @@ -1,4 +1,4 @@ -package com.mindee.v2.parsing; +package com.mindee.v2.product; import static com.mindee.TestingUtilities.getV2ResourcePath; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -11,7 +11,7 @@ import com.mindee.geometry.Point; import com.mindee.geometry.Polygon; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.parsing.inference.InferenceActiveOptions; import com.mindee.v2.parsing.inference.InferenceFile; import com.mindee.v2.parsing.inference.InferenceJob; diff --git a/src/test/java/com/mindee/v2/product/OcrTest.java b/src/test/java/com/mindee/v2/product/OcrTest.java index ef734eec0..92f5b8aad 100644 --- a/src/test/java/com/mindee/v2/product/OcrTest.java +++ b/src/test/java/com/mindee/v2/product/OcrTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.product.ocr.OcrResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/product/SplitTest.java b/src/test/java/com/mindee/v2/product/SplitTest.java index d4ff870d1..f21b452cf 100644 --- a/src/test/java/com/mindee/v2/product/SplitTest.java +++ b/src/test/java/com/mindee/v2/product/SplitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.input.LocalResponse; +import com.mindee.v2.input.LocalResponse; import com.mindee.v2.product.split.SplitResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; From c373a532bc33878d4992cbb789a46c76f7a61368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ianar=C3=A9=20S=C3=A9vi?= Date: Tue, 7 Apr 2026 17:05:20 +0200 Subject: [PATCH 2/3] fix for misleading error message --- ...alResponse.java => BaseLocalResponse.java} | 13 ++-- src/main/java/com/mindee/v1/MindeeClient.java | 27 -------- .../com/mindee/v1/input/LocalResponse.java | 62 ++++++++++--------- .../com/mindee/v2/input/LocalResponse.java | 9 +-- .../java/com/mindee/v1/MindeeClientTest.java | 31 ---------- .../mindee/v1/input/LocalResponseTest.java | 43 +++++++++++-- 6 files changed, 82 insertions(+), 103 deletions(-) rename src/main/java/com/mindee/input/{LocalResponse.java => BaseLocalResponse.java} (87%) diff --git a/src/main/java/com/mindee/input/LocalResponse.java b/src/main/java/com/mindee/input/BaseLocalResponse.java similarity index 87% rename from src/main/java/com/mindee/input/LocalResponse.java rename to src/main/java/com/mindee/input/BaseLocalResponse.java index 736006c13..1442bb491 100644 --- a/src/main/java/com/mindee/input/LocalResponse.java +++ b/src/main/java/com/mindee/input/BaseLocalResponse.java @@ -21,7 +21,7 @@ * A Mindee response saved locally. */ @Getter -public abstract class LocalResponse { +public abstract class BaseLocalResponse { protected final byte[] file; /** @@ -29,7 +29,7 @@ public abstract class LocalResponse { * * @param input will be decoded as UTF-8. */ - public LocalResponse(InputStream input) { + public BaseLocalResponse(InputStream input) { this.file = this .getBytes(new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines()); } @@ -39,7 +39,10 @@ public LocalResponse(InputStream input) { * * @param input will be decoded as UTF-8. */ - public LocalResponse(String input) { + public BaseLocalResponse(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("Input string cannot be empty or null."); + } this.file = input.getBytes(StandardCharsets.UTF_8); } @@ -48,7 +51,7 @@ public LocalResponse(String input) { * * @param input will be decoded as UTF-8. */ - public LocalResponse(File input) throws IOException { + public BaseLocalResponse(File input) throws IOException { this.file = this.getBytes(Files.lines(input.toPath(), StandardCharsets.UTF_8)); } @@ -57,7 +60,7 @@ public LocalResponse(File input) throws IOException { * * @param input will be decoded as UTF-8. */ - public LocalResponse(Path input) throws IOException { + public BaseLocalResponse(Path input) throws IOException { this.file = this.getBytes(Files.lines(input, StandardCharsets.UTF_8)); } diff --git a/src/main/java/com/mindee/v1/MindeeClient.java b/src/main/java/com/mindee/v1/MindeeClient.java index 7c401c04a..f9c3ea5b3 100644 --- a/src/main/java/com/mindee/v1/MindeeClient.java +++ b/src/main/java/com/mindee/v1/MindeeClient.java @@ -1,12 +1,9 @@ package com.mindee.v1; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.AsyncPollingOptions; import com.mindee.MindeeException; import com.mindee.input.InputSourceUtils; import com.mindee.input.LocalInputSource; -import com.mindee.input.LocalResponse; import com.mindee.input.PageOptions; import com.mindee.pdf.PdfBoxApi; import com.mindee.pdf.PdfOperation; @@ -1071,28 +1068,4 @@ public AsyncPredictResponse parseQueued( ) { return this.mindeeApi.documentQueueGet(type, endpoint, jobId); } - - /** - * Load a local prediction. - * Typically used when wanting to load from a webhook callback. - * However, any kind of Mindee response may be loaded. - * - * @param Type of inference. - * @param type Type of inference. - * @param localResponse A loaded local response. - * @return an instance of {@link AsyncPredictResponse}. - * @throws IOException Throws if the file can't be accessed. - */ - public AsyncPredictResponse loadPrediction( - Class type, - LocalResponse localResponse - ) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.findAndRegisterModules(); - JavaType parametricType = objectMapper - .getTypeFactory() - .constructParametricType(AsyncPredictResponse.class, type); - return objectMapper.readValue(localResponse.getFile(), parametricType); - } - } diff --git a/src/main/java/com/mindee/v1/input/LocalResponse.java b/src/main/java/com/mindee/v1/input/LocalResponse.java index 1791e2aeb..be3c1b201 100644 --- a/src/main/java/com/mindee/v1/input/LocalResponse.java +++ b/src/main/java/com/mindee/v1/input/LocalResponse.java @@ -1,7 +1,9 @@ package com.mindee.v1.input; +import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.MindeeException; +import com.mindee.input.BaseLocalResponse; import com.mindee.v1.parsing.common.AsyncPredictResponse; import com.mindee.v1.parsing.common.Inference; import com.mindee.v1.parsing.common.PredictResponse; @@ -14,7 +16,7 @@ /** * A Mindee response saved locally. */ -public class LocalResponse extends com.mindee.input.LocalResponse { +public class LocalResponse extends BaseLocalResponse { public LocalResponse(InputStream input) { super(input); @@ -32,52 +34,52 @@ public LocalResponse(Path input) throws IOException { super(input); } + private

R deserialize( + Class responseClass, + Class

productClass + ) throws IOException { + var mapper = new ObjectMapper().findAndRegisterModules(); + var type = mapper.getTypeFactory().constructParametricType(responseClass, productClass); + try { + return mapper.readValue(this.file, type); + } catch (Exception e) { + if (e instanceof JacksonException) { + throw new MindeeException("Invalid JSON payload.", e); + } + throw e; + } + } + /** * Deserialize this local JSON payload into a specific {@link AsyncPredictResponse}. * subtype: {@code InferenceResponse}, {@code JobResponse}. * - * @param responseClass the concrete class to instantiate + * @param productClass the concrete class to instantiate * @param generic {@link Inference} * @return A {@link AsyncPredictResponse} instance. * @throws MindeeException if the payload cannot be deserialized into the requested type */ public AsyncPredictResponse deserializeAsyncResponse( - Class responseClass - ) { - var objectMapper = new ObjectMapper(); - objectMapper.findAndRegisterModules(); - var type = objectMapper - .getTypeFactory() - .constructParametricType(AsyncPredictResponse.class, responseClass); - try { - AsyncPredictResponse response = objectMapper.readValue(this.file, type); - response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); - return response; - } catch (Exception ex) { - throw new MindeeException("Invalid class specified for deserialization.", ex); - } + Class productClass + ) throws IOException { + AsyncPredictResponse response = deserialize(AsyncPredictResponse.class, productClass); + response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); + return response; } /** * Deserialize this local JSON payload into a specific {@link PredictResponse}. * - * @param responseClass the concrete class to instantiate + * @param productClass the concrete class to instantiate * @param generic {@link Inference} * @return A {@link PredictResponse} instance. * @throws MindeeException if the payload cannot be deserialized into the requested type */ - public PredictResponse deserializeSyncResponse(Class responseClass) { - var objectMapper = new ObjectMapper(); - objectMapper.findAndRegisterModules(); - var type = objectMapper - .getTypeFactory() - .constructParametricType(PredictResponse.class, responseClass); - try { - PredictResponse response = objectMapper.readValue(this.file, type); - response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); - return response; - } catch (Exception ex) { - throw new MindeeException("Invalid class specified for deserialization.", ex); - } + public PredictResponse deserializeSyncResponse( + Class productClass + ) throws IOException { + PredictResponse response = deserialize(PredictResponse.class, productClass); + response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); + return response; } } diff --git a/src/main/java/com/mindee/v2/input/LocalResponse.java b/src/main/java/com/mindee/v2/input/LocalResponse.java index d06c373e9..4135fc2bd 100644 --- a/src/main/java/com/mindee/v2/input/LocalResponse.java +++ b/src/main/java/com/mindee/v2/input/LocalResponse.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.MindeeException; +import com.mindee.input.BaseLocalResponse; import com.mindee.v2.parsing.CommonResponse; import java.io.File; import java.io.IOException; @@ -12,7 +13,7 @@ /** * A Mindee response saved locally. */ -public class LocalResponse extends com.mindee.input.LocalResponse { +public class LocalResponse extends BaseLocalResponse { public LocalResponse(InputStream input) { super(input); @@ -40,13 +41,13 @@ public LocalResponse(Path input) throws IOException { * @throws MindeeException if the payload cannot be deserialized into the requested type */ public T deserializeResponse(Class responseClass) { - var mapper = new ObjectMapper(); + var mapper = new ObjectMapper().findAndRegisterModules(); try { var response = mapper.readValue(this.file, responseClass); response.setRawResponse(new String(this.file, StandardCharsets.UTF_8)); return response; - } catch (Exception ex) { - throw new MindeeException("Invalid class specified for deserialization.", ex); + } catch (Exception e) { + throw new MindeeException("Invalid JSON payload.", e); } } } diff --git a/src/test/java/com/mindee/v1/MindeeClientTest.java b/src/test/java/com/mindee/v1/MindeeClientTest.java index dceae5b4f..c2cc65079 100644 --- a/src/test/java/com/mindee/v1/MindeeClientTest.java +++ b/src/test/java/com/mindee/v1/MindeeClientTest.java @@ -1,21 +1,16 @@ package com.mindee.v1; -import static com.mindee.TestingUtilities.assertStringEqualsFile; import static com.mindee.TestingUtilities.getResourcePath; -import static com.mindee.TestingUtilities.getV1ResourcePathString; import com.mindee.input.LocalInputSource; import com.mindee.input.PageOptions; import com.mindee.input.PageOptionsOperation; import com.mindee.v1.clientOptions.PredictOptions; -import com.mindee.v1.input.LocalResponse; import com.mindee.v1.parsing.common.AsyncPredictResponse; import com.mindee.v1.parsing.common.Document; import com.mindee.v1.parsing.common.Job; import com.mindee.v1.parsing.common.PredictResponse; -import com.mindee.v1.product.internationalid.InternationalIdV2; import com.mindee.v1.product.invoice.InvoiceV4; -import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; @@ -156,30 +151,4 @@ void givenAnAsyncUrl_whenEnqueued_shouldInvokeApiCorrectly() throws IOException Assertions.assertEquals("someid", jobId); } - - @Test - void givenJsonInput_whenSync_shouldDeserializeCorrectly() throws IOException { - File file = new File(getV1ResourcePathString("products/invoices/response_v4/complete.json")); - LocalResponse localResponse = new LocalResponse(file); - AsyncPredictResponse predictResponse = new MindeeClient() - .loadPrediction(InvoiceV4.class, localResponse); - assertStringEqualsFile( - predictResponse.getDocumentObj().toString(), - getV1ResourcePathString("/products/invoices/response_v4/summary_full.rst") - ); - } - - @Test - void givenJsonInput_whenAsync_shouldDeserializeCorrectly() throws IOException { - File file = new File( - getV1ResourcePathString("products/international_id/response_v2/complete.json") - ); - LocalResponse localResponse = new LocalResponse(file); - AsyncPredictResponse predictResponse = new MindeeClient() - .loadPrediction(InternationalIdV2.class, localResponse); - assertStringEqualsFile( - predictResponse.getDocumentObj().toString(), - getV1ResourcePathString("products/international_id/response_v2/summary_full.rst") - ); - } } diff --git a/src/test/java/com/mindee/v1/input/LocalResponseTest.java b/src/test/java/com/mindee/v1/input/LocalResponseTest.java index 5fd6bc8b3..29432ff11 100644 --- a/src/test/java/com/mindee/v1/input/LocalResponseTest.java +++ b/src/test/java/com/mindee/v1/input/LocalResponseTest.java @@ -1,8 +1,12 @@ package com.mindee.v1.input; +import static com.mindee.TestingUtilities.assertStringEqualsFile; import static com.mindee.TestingUtilities.getV1ResourcePath; +import static com.mindee.TestingUtilities.getV1ResourcePathString; +import com.mindee.MindeeException; import com.mindee.v1.product.internationalid.InternationalIdV2; +import com.mindee.v1.product.invoice.InvoiceV4; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -36,10 +40,6 @@ void loadDocument_withFile_mustReturnValidLocalResponse() throws IOException { ); Assertions.assertEquals(this.signature, localResponse.getHmacSignature(this.secretKey)); Assertions.assertTrue(localResponse.isValidHmacSignature(this.secretKey, this.signature)); - - var response = localResponse.deserializeAsyncResponse(InternationalIdV2.class); - Assertions.assertNotNull(response); - Assertions.assertNotNull(response.getDocumentObj()); } @Test @@ -62,9 +62,40 @@ void loadDocument_withInputStream_mustReturnValidLocalResponse() throws IOExcept ); Assertions.assertEquals(this.signature, localResponse.getHmacSignature(this.secretKey)); Assertions.assertTrue(localResponse.isValidHmacSignature(this.secretKey, this.signature)); + } + + @Test + void givenJsonInput_whenSync_shouldDeserializeCorrectly() throws IOException { + var localResponse = new LocalResponse( + getV1ResourcePath("products/invoices/response_v4/complete.json") + ); + var response = localResponse.deserializeSyncResponse(InvoiceV4.class); + assertStringEqualsFile( + response.getDocument().toString(), + getV1ResourcePath("/products/invoices/response_v4/summary_full.rst") + ); + } + @Test + void givenJsonInput_whenAsync_shouldDeserializeCorrectly() throws IOException { + var localResponse = new LocalResponse( + getV1ResourcePath("products/international_id/response_v2/complete.json") + ); var response = localResponse.deserializeAsyncResponse(InternationalIdV2.class); - Assertions.assertNotNull(response); - Assertions.assertNotNull(response.getDocumentObj()); + assertStringEqualsFile( + response.getDocumentObj().toString(), + getV1ResourcePathString("products/international_id/response_v2/summary_full.rst") + ); + } + + @Test + void givenInvalidJsonInput_shouldThrow() { + var localResponse = new LocalResponse("{invalid json"); + var err = Assertions + .assertThrows( + MindeeException.class, + () -> localResponse.deserializeSyncResponse(InvoiceV4.class) + ); + Assertions.assertEquals("Invalid JSON payload.", err.getMessage()); } } From f116dd488865fac6308c57e7b9565850b966e382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ianar=C3=A9=20S=C3=A9vi?= Date: Tue, 7 Apr 2026 17:13:14 +0200 Subject: [PATCH 3/3] move to parsing --- .../{input => parsing}/BaseLocalResponse.java | 2 +- .../v1/{input => parsing}/LocalResponse.java | 4 +- .../v2/{input => parsing}/LocalResponse.java | 5 +- .../{input => parsing}/LocalResponseTest.java | 2 +- .../java/com/mindee/v2/MindeeClientTest.java | 43 +--------------- .../mindee/v2/input/LocalResponseTest.java | 1 + .../java/com/mindee/v2/parsing/JobTest.java | 1 - .../mindee/v2/parsing/LocalResponseTest.java | 50 +++++++++++++++++++ .../mindee/v2/product/ClassificationTest.java | 2 +- .../java/com/mindee/v2/product/CropTest.java | 2 +- .../com/mindee/v2/product/ExtractionTest.java | 2 +- .../java/com/mindee/v2/product/OcrTest.java | 2 +- .../java/com/mindee/v2/product/SplitTest.java | 2 +- 13 files changed, 64 insertions(+), 54 deletions(-) rename src/main/java/com/mindee/{input => parsing}/BaseLocalResponse.java (99%) rename src/main/java/com/mindee/v1/{input => parsing}/LocalResponse.java (97%) rename src/main/java/com/mindee/v2/{input => parsing}/LocalResponse.java (92%) rename src/test/java/com/mindee/v1/{input => parsing}/LocalResponseTest.java (99%) create mode 100644 src/test/java/com/mindee/v2/parsing/LocalResponseTest.java diff --git a/src/main/java/com/mindee/input/BaseLocalResponse.java b/src/main/java/com/mindee/parsing/BaseLocalResponse.java similarity index 99% rename from src/main/java/com/mindee/input/BaseLocalResponse.java rename to src/main/java/com/mindee/parsing/BaseLocalResponse.java index 1442bb491..3284e9984 100644 --- a/src/main/java/com/mindee/input/BaseLocalResponse.java +++ b/src/main/java/com/mindee/parsing/BaseLocalResponse.java @@ -1,4 +1,4 @@ -package com.mindee.input; +package com.mindee.parsing; import java.io.BufferedReader; import java.io.File; diff --git a/src/main/java/com/mindee/v1/input/LocalResponse.java b/src/main/java/com/mindee/v1/parsing/LocalResponse.java similarity index 97% rename from src/main/java/com/mindee/v1/input/LocalResponse.java rename to src/main/java/com/mindee/v1/parsing/LocalResponse.java index be3c1b201..b9244d014 100644 --- a/src/main/java/com/mindee/v1/input/LocalResponse.java +++ b/src/main/java/com/mindee/v1/parsing/LocalResponse.java @@ -1,9 +1,9 @@ -package com.mindee.v1.input; +package com.mindee.v1.parsing; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.MindeeException; -import com.mindee.input.BaseLocalResponse; +import com.mindee.parsing.BaseLocalResponse; import com.mindee.v1.parsing.common.AsyncPredictResponse; import com.mindee.v1.parsing.common.Inference; import com.mindee.v1.parsing.common.PredictResponse; diff --git a/src/main/java/com/mindee/v2/input/LocalResponse.java b/src/main/java/com/mindee/v2/parsing/LocalResponse.java similarity index 92% rename from src/main/java/com/mindee/v2/input/LocalResponse.java rename to src/main/java/com/mindee/v2/parsing/LocalResponse.java index 4135fc2bd..33ec16410 100644 --- a/src/main/java/com/mindee/v2/input/LocalResponse.java +++ b/src/main/java/com/mindee/v2/parsing/LocalResponse.java @@ -1,9 +1,8 @@ -package com.mindee.v2.input; +package com.mindee.v2.parsing; import com.fasterxml.jackson.databind.ObjectMapper; import com.mindee.MindeeException; -import com.mindee.input.BaseLocalResponse; -import com.mindee.v2.parsing.CommonResponse; +import com.mindee.parsing.BaseLocalResponse; import java.io.File; import java.io.IOException; import java.io.InputStream; diff --git a/src/test/java/com/mindee/v1/input/LocalResponseTest.java b/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java similarity index 99% rename from src/test/java/com/mindee/v1/input/LocalResponseTest.java rename to src/test/java/com/mindee/v1/parsing/LocalResponseTest.java index 29432ff11..981fb194b 100644 --- a/src/test/java/com/mindee/v1/input/LocalResponseTest.java +++ b/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java @@ -1,4 +1,4 @@ -package com.mindee.v1.input; +package com.mindee.v1.parsing; import static com.mindee.TestingUtilities.assertStringEqualsFile; import static com.mindee.TestingUtilities.getV1ResourcePath; diff --git a/src/test/java/com/mindee/v2/MindeeClientTest.java b/src/test/java/com/mindee/v2/MindeeClientTest.java index 32bc0ade4..b3e5f1da6 100644 --- a/src/test/java/com/mindee/v2/MindeeClientTest.java +++ b/src/test/java/com/mindee/v2/MindeeClientTest.java @@ -10,7 +10,6 @@ import com.mindee.input.URLInputSource; import com.mindee.v2.clientOptions.BaseParameters; import com.mindee.v2.http.MindeeApiV2; -import com.mindee.v2.input.LocalResponse; import com.mindee.v2.parsing.CommonResponse; import com.mindee.v2.parsing.JobResponse; import com.mindee.v2.product.extraction.ExtractionResponse; @@ -34,18 +33,12 @@ public FakeMindeeApiV2(JobResponse jobResponse, CommonResponse resultResponse) { } @Override - public JobResponse reqPostEnqueue( - LocalInputSource inputSource, - BaseParameters options - ) throws IOException { + public JobResponse reqPostEnqueue(LocalInputSource inputSource, BaseParameters options) { return jobResponse; } @Override - public JobResponse reqPostEnqueue( - URLInputSource inputSource, - BaseParameters options - ) throws IOException { + public JobResponse reqPostEnqueue(URLInputSource inputSource, BaseParameters options) { return jobResponse; } @@ -136,36 +129,4 @@ void document_getResult_async() throws IOException { ); } } - - @Nested - @DisplayName("deserializeResponse()") - class DeserializeResponse { - - @Test - @DisplayName("parses local JSON and exposes correct field values") - void inference_loadsLocally() throws IOException { - var localResponse = new LocalResponse( - getResourcePath("v2/products/extraction/financial_document/complete.json") - ); - ExtractionResponse loaded = localResponse.deserializeResponse(ExtractionResponse.class); - - assertNotNull(loaded, "Loaded InferenceResponse must not be null"); - assertEquals( - "12345678-1234-1234-1234-123456789abc", - loaded.getInference().getModel().getId(), - "Model Id mismatch" - ); - assertEquals( - "John Smith", - loaded - .getInference() - .getResult() - .getFields() - .get("supplier_name") - .getSimpleField() - .getValue(), - "Supplier name mismatch" - ); - } - } } diff --git a/src/test/java/com/mindee/v2/input/LocalResponseTest.java b/src/test/java/com/mindee/v2/input/LocalResponseTest.java index f898f94a6..860d83095 100644 --- a/src/test/java/com/mindee/v2/input/LocalResponseTest.java +++ b/src/test/java/com/mindee/v2/input/LocalResponseTest.java @@ -2,6 +2,7 @@ import static com.mindee.TestingUtilities.getV2ResourcePath; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.product.extraction.ExtractionResponse; import java.io.File; import java.io.IOException; diff --git a/src/test/java/com/mindee/v2/parsing/JobTest.java b/src/test/java/com/mindee/v2/parsing/JobTest.java index 71951ceca..77e97ffd1 100644 --- a/src/test/java/com/mindee/v2/parsing/JobTest.java +++ b/src/test/java/com/mindee/v2/parsing/JobTest.java @@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import com.mindee.v2.input.LocalResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java b/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java new file mode 100644 index 000000000..ad59a14e3 --- /dev/null +++ b/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java @@ -0,0 +1,50 @@ +package com.mindee.v2.parsing; + +import static com.mindee.TestingUtilities.getResourcePath; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.mindee.MindeeException; +import com.mindee.v2.product.extraction.ExtractionResponse; +import java.io.IOException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LocalResponseTest { + @Test + void loadDocument_withPath_mustReturnValidLocalResponse() throws IOException { + var localResponse = new LocalResponse( + getResourcePath("v2/products/extraction/financial_document/complete.json") + ); + ExtractionResponse loaded = localResponse.deserializeResponse(ExtractionResponse.class); + + assertNotNull(loaded, "Loaded InferenceResponse must not be null"); + assertEquals( + "12345678-1234-1234-1234-123456789abc", + loaded.getInference().getModel().getId(), + "Model Id mismatch" + ); + assertEquals( + "John Smith", + loaded + .getInference() + .getResult() + .getFields() + .get("supplier_name") + .getSimpleField() + .getValue(), + "Supplier name mismatch" + ); + } + + @Test + void givenInvalidJsonInput_shouldThrow() { + var localResponse = new LocalResponse("{invalid json"); + var err = Assertions + .assertThrows( + MindeeException.class, + () -> localResponse.deserializeResponse(ExtractionResponse.class) + ); + Assertions.assertEquals("Invalid JSON payload.", err.getMessage()); + } +} diff --git a/src/test/java/com/mindee/v2/product/ClassificationTest.java b/src/test/java/com/mindee/v2/product/ClassificationTest.java index b457eff43..624b5020b 100644 --- a/src/test/java/com/mindee/v2/product/ClassificationTest.java +++ b/src/test/java/com/mindee/v2/product/ClassificationTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.v2.input.LocalResponse; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.product.classification.ClassificationResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/product/CropTest.java b/src/test/java/com/mindee/v2/product/CropTest.java index 9fbedbad1..5798aa523 100644 --- a/src/test/java/com/mindee/v2/product/CropTest.java +++ b/src/test/java/com/mindee/v2/product/CropTest.java @@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.v2.input.LocalResponse; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.product.crop.CropResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/product/ExtractionTest.java b/src/test/java/com/mindee/v2/product/ExtractionTest.java index 6d1e790bf..724e37639 100644 --- a/src/test/java/com/mindee/v2/product/ExtractionTest.java +++ b/src/test/java/com/mindee/v2/product/ExtractionTest.java @@ -11,7 +11,7 @@ import com.mindee.geometry.Point; import com.mindee.geometry.Polygon; -import com.mindee.v2.input.LocalResponse; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.parsing.inference.InferenceActiveOptions; import com.mindee.v2.parsing.inference.InferenceFile; import com.mindee.v2.parsing.inference.InferenceJob; diff --git a/src/test/java/com/mindee/v2/product/OcrTest.java b/src/test/java/com/mindee/v2/product/OcrTest.java index 92f5b8aad..ae269073e 100644 --- a/src/test/java/com/mindee/v2/product/OcrTest.java +++ b/src/test/java/com/mindee/v2/product/OcrTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.v2.input.LocalResponse; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.product.ocr.OcrResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/com/mindee/v2/product/SplitTest.java b/src/test/java/com/mindee/v2/product/SplitTest.java index f21b452cf..b3db37ff4 100644 --- a/src/test/java/com/mindee/v2/product/SplitTest.java +++ b/src/test/java/com/mindee/v2/product/SplitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.mindee.v2.input.LocalResponse; +import com.mindee.v2.parsing.LocalResponse; import com.mindee.v2.product.split.SplitResponse; import java.io.IOException; import org.junit.jupiter.api.DisplayName;