From 2357205d58e65d3f1608495da007e9cb02c5d099 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Wed, 14 Feb 2024 12:26:19 -0800 Subject: [PATCH 1/5] Adds error payload to DaprException. Signed-off-by: Artur Souza --- .../io/dapr/examples/exception/Client.java | 8 +-- .../java/io/dapr/examples/exception/README.md | 4 ++ .../src/test/java/io/dapr/it/TestUtils.java | 4 +- .../main/java/io/dapr/client/DaprHttp.java | 11 +++-- .../io/dapr/exceptions/DaprException.java | 49 +++++++++++++++---- .../io/dapr/client/DaprClientHttpTest.java | 3 +- .../java/io/dapr/client/DaprHttpTest.java | 2 +- .../test/java/io/dapr/utils/TestUtils.java | 3 +- 8 files changed, 57 insertions(+), 27 deletions(-) diff --git a/examples/src/main/java/io/dapr/examples/exception/Client.java b/examples/src/main/java/io/dapr/examples/exception/Client.java index fb69a5125..386c26690 100644 --- a/examples/src/main/java/io/dapr/examples/exception/Client.java +++ b/examples/src/main/java/io/dapr/examples/exception/Client.java @@ -19,11 +19,6 @@ import io.dapr.exceptions.DaprException; import io.dapr.utils.TypeRef; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * 1. Build and install jars: * mvn clean install @@ -45,10 +40,11 @@ public static void main(String[] args) throws Exception { } catch (DaprException exception) { System.out.println("Error code: " + exception.getErrorCode()); System.out.println("Error message: " + exception.getMessage()); - System.out.println("Reason: " + exception.getStatusDetails().get( + System.out.println("Reason: " + exception.getErrorDetails().get( DaprErrorDetails.ErrorDetailType.ERROR_INFO, "reason", TypeRef.STRING)); + System.out.println("Error's payload size: " + exception.getPayload().length); } } System.out.println("Done"); diff --git a/examples/src/main/java/io/dapr/examples/exception/README.md b/examples/src/main/java/io/dapr/examples/exception/README.md index ff1e6182e..0776f614b 100644 --- a/examples/src/main/java/io/dapr/examples/exception/README.md +++ b/examples/src/main/java/io/dapr/examples/exception/README.md @@ -50,6 +50,7 @@ public class Client { DaprErrorDetails.ErrorDetailType.ERROR_INFO, "reason", TypeRef.STRING)); + System.out.println("Error's payload size: " + exception.getPayload().length); } } System.out.println("Done"); @@ -66,6 +67,7 @@ expected_stdout_lines: - '== APP == Error code: INVALID_ARGUMENT' - '== APP == Error message: INVALID_ARGUMENT: pubsub unknown_pubsub is not found' - '== APP == Reason: DAPR_PUBSUB_NOT_FOUND' + - '== APP == Error's payload size: 116' background: true sleep: 5 --> @@ -84,6 +86,8 @@ Once running, the State Client Example should print the output as follows: == APP == Error message: ERR_PUBSUB_NOT_FOUND: pubsub unknown_pubsub is not found == APP == Reason: DAPR_PUBSUB_NOT_FOUND + +== APP == Error's payload size: 116 ... ``` diff --git a/sdk-tests/src/test/java/io/dapr/it/TestUtils.java b/sdk-tests/src/test/java/io/dapr/it/TestUtils.java index a9ef0354d..ce836d4cd 100644 --- a/sdk-tests/src/test/java/io/dapr/it/TestUtils.java +++ b/sdk-tests/src/test/java/io/dapr/it/TestUtils.java @@ -52,10 +52,10 @@ public static void assertThrowsDaprExceptionWithReason( DaprException daprException = Assertions.assertThrows(DaprException.class, executable); Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode()); Assertions.assertEquals(expectedErrorMessage, daprException.getMessage()); - Assertions.assertNotNull(daprException.getStatusDetails()); + Assertions.assertNotNull(daprException.getErrorDetails()); Assertions.assertEquals( expectedReason, - daprException.getStatusDetails().get( + daprException.getErrorDetails().get( DaprErrorDetails.ErrorDetailType.ERROR_INFO, "reason", TypeRef.STRING diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 2102fa84c..f9f470d9b 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -350,7 +350,7 @@ private static DaprError parseDaprError(byte[] json) { try { return DAPR_ERROR_DETAILS_OBJECT_MAPPER.readValue(json, DaprError.class); } catch (IOException e) { - throw new DaprException("UNKNOWN", new String(json, StandardCharsets.UTF_8)); + throw new DaprException("UNKNOWN", "Could not parse error's payload.", json); } } @@ -383,18 +383,19 @@ public void onFailure(Call call, IOException e) { public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) throws IOException { if (!response.isSuccessful()) { try { - DaprError error = parseDaprError(getBodyBytesOrEmptyArray(response)); + byte[] payload = getBodyBytesOrEmptyArray(response); + DaprError error = parseDaprError(payload); if ((error != null) && (error.getErrorCode() != null)) { if (error.getMessage() != null) { - future.completeExceptionally(new DaprException(error)); + future.completeExceptionally(new DaprException(error, payload)); } else { future.completeExceptionally( - new DaprException(error.getErrorCode(), "HTTP status code: " + response.code())); + new DaprException(error.getErrorCode(), "HTTP status code: " + response.code(), payload)); } return; } - future.completeExceptionally(new DaprException("UNKNOWN", "HTTP status code: " + response.code())); + future.completeExceptionally(new DaprException("UNKNOWN", "HTTP status code: " + response.code(), payload)); return; } catch (DaprException e) { future.completeExceptionally(e); diff --git a/sdk/src/main/java/io/dapr/exceptions/DaprException.java b/sdk/src/main/java/io/dapr/exceptions/DaprException.java index f87eb79e7..40d48530f 100644 --- a/sdk/src/main/java/io/dapr/exceptions/DaprException.java +++ b/sdk/src/main/java/io/dapr/exceptions/DaprException.java @@ -37,13 +37,19 @@ public class DaprException extends RuntimeException { */ private DaprErrorDetails errorDetails; + /** + * Optional payload, if the exception came from a response body. + */ + private byte[] payload; + /** * New exception from a server-side generated error code and message. * * @param daprError Server-side error. + * @param payload Payload containing the error. */ - public DaprException(DaprError daprError) { - this(daprError.getErrorCode(), daprError.getMessage(), daprError.getDetails()); + public DaprException(DaprError daprError, byte[] payload) { + this(daprError.getErrorCode(), daprError.getMessage(), daprError.getDetails(), payload); } /** @@ -71,9 +77,10 @@ public DaprException(Throwable exception) { * * @param errorCode Client-side error code. * @param message Client-side error message. + * @param payload Error's raw payload. */ - public DaprException(String errorCode, String message) { - this(errorCode, message, DaprErrorDetails.EMPTY_INSTANCE); + public DaprException(String errorCode, String message, byte[] payload) { + this(errorCode, message, DaprErrorDetails.EMPTY_INSTANCE, payload); } /** @@ -82,9 +89,10 @@ public DaprException(String errorCode, String message) { * @param errorCode Client-side error code. * @param message Client-side error message. * @param errorDetails Details of the error from runtime. + * @param payload Payload containing the error. */ - public DaprException(String errorCode, String message, List> errorDetails) { - this(errorCode, message, new DaprErrorDetails(errorDetails)); + public DaprException(String errorCode, String message, List> errorDetails, byte[] payload) { + this(errorCode, message, new DaprErrorDetails(errorDetails), payload); } /** @@ -93,11 +101,13 @@ public DaprException(String errorCode, String message, List> * @param errorCode Client-side error code. * @param message Client-side error message. * @param errorDetails Details of the error from runtime. + * @param payload Payload containing the error. */ - public DaprException(String errorCode, String message, DaprErrorDetails errorDetails) { + public DaprException(String errorCode, String message, DaprErrorDetails errorDetails, byte[] payload) { super(String.format("%s: %s", errorCode, message)); this.errorCode = errorCode; this.errorDetails = errorDetails; + this.payload = payload; } /** @@ -123,11 +133,14 @@ public DaprException(String errorCode, String message, Throwable cause) { * permitted, and indicates that the cause is nonexistent or * unknown.) * @param errorDetails the status details for the error. + * @param payload Raw error payload. */ - public DaprException(String errorCode, String message, Throwable cause, DaprErrorDetails errorDetails) { + public DaprException( + String errorCode, String message, Throwable cause, DaprErrorDetails errorDetails, byte[] payload) { super(String.format("%s: %s", errorCode, emptyIfNull(message)), cause); this.errorCode = errorCode; this.errorDetails = errorDetails == null ? DaprErrorDetails.EMPTY_INSTANCE : errorDetails; + this.payload = payload; } /** @@ -139,10 +152,24 @@ public String getErrorCode() { return this.errorCode; } - public DaprErrorDetails getStatusDetails() { + /** + * Returns the exception's error details. + * + * @return Error details. + */ + public DaprErrorDetails getErrorDetails() { return this.errorDetails; } + /** + * Returns the exception's error payload (optional). + * + * @return Error's payload. + */ + public byte[] getPayload() { + return this.payload == null ? null : this.payload.clone(); + } + /** * Wraps an exception into DaprException (if not already DaprException). * @@ -247,7 +274,9 @@ public static RuntimeException propagate(Throwable exception) { statusRuntimeException.getStatus().getCode().toString(), statusRuntimeException.getStatus().getDescription(), exception, - errorDetails); + errorDetails, + status.toByteArray()); + } e = e.getCause(); diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index 85235f144..a780bfdb9 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -387,7 +387,8 @@ public void invokeServiceDaprErrorUnknownJSON() { }); assertEquals("UNKNOWN", exception.getErrorCode()); - assertEquals("UNKNOWN: { \"anything\": 7 }", exception.getMessage()); + assertEquals("UNKNOWN: Could not parse error's payload.", exception.getMessage()); + assertEquals("{ \"anything\": 7 }", new String(exception.getPayload())); } @Test diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index ae121e455..dac27904b 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -236,7 +236,7 @@ public void validateExceptionParsing() { DaprException daprException = (DaprException)e; assertEquals("ERR_PUBSUB_NOT_FOUND", daprException.getErrorCode()); assertEquals("DAPR_PUBSUB_NOT_FOUND", - daprException.getStatusDetails() + daprException.getErrorDetails() .get(DaprErrorDetails.ErrorDetailType.ERROR_INFO, "reason", TypeRef.STRING)); return true; }).verify(); diff --git a/sdk/src/test/java/io/dapr/utils/TestUtils.java b/sdk/src/test/java/io/dapr/utils/TestUtils.java index a53449d1a..592db3a98 100644 --- a/sdk/src/test/java/io/dapr/utils/TestUtils.java +++ b/sdk/src/test/java/io/dapr/utils/TestUtils.java @@ -20,7 +20,6 @@ import java.io.IOException; import java.net.ServerSocket; -import java.util.Map; public final class TestUtils { @@ -71,7 +70,7 @@ public static void assertThrowsDaprException( Assertions.assertEquals(expectedType, daprException.getCause().getClass()); Assertions.assertEquals(expectedErrorCode, daprException.getErrorCode()); Assertions.assertEquals(expectedErrorMessage, daprException.getMessage()); - Assertions.assertEquals(expectedStatusDetails, daprException.getStatusDetails()); + Assertions.assertEquals(expectedStatusDetails, daprException.getErrorDetails()); } public static int findFreePort() throws IOException { From bd0b6c01158b47c46e541268740ba02814d800cd Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Thu, 15 Feb 2024 08:28:40 -0800 Subject: [PATCH 2/5] Keep having http payload in exception message. Signed-off-by: Artur Souza --- .../test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java | 1 + sdk/src/main/java/io/dapr/client/DaprHttp.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java index 3687bd805..0cf9e42f5 100644 --- a/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/methodinvoke/http/MethodInvokeIT.java @@ -136,6 +136,7 @@ public void testInvokeException() throws Exception { assertEquals("UNKNOWN", exception.getErrorCode()); assertNotNull(exception.getMessage()); assertTrue(exception.getMessage().contains("Internal Server Error")); + assertTrue(new String(exception.getPayload()).contains("Internal Server Error")); } } } diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index f9f470d9b..08c9cc670 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -350,7 +350,7 @@ private static DaprError parseDaprError(byte[] json) { try { return DAPR_ERROR_DETAILS_OBJECT_MAPPER.readValue(json, DaprError.class); } catch (IOException e) { - throw new DaprException("UNKNOWN", "Could not parse error's payload.", json); + throw new DaprException("UNKNOWN", new String(json), json); } } From 9df94294f1ea43ffc571dd2f0629f8a91283ce11 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Thu, 15 Feb 2024 08:40:32 -0800 Subject: [PATCH 3/5] Fix example output. Signed-off-by: Artur Souza --- examples/src/main/java/io/dapr/examples/exception/Client.java | 2 +- examples/src/main/java/io/dapr/examples/exception/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/src/main/java/io/dapr/examples/exception/Client.java b/examples/src/main/java/io/dapr/examples/exception/Client.java index 386c26690..635b66bbb 100644 --- a/examples/src/main/java/io/dapr/examples/exception/Client.java +++ b/examples/src/main/java/io/dapr/examples/exception/Client.java @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { DaprErrorDetails.ErrorDetailType.ERROR_INFO, "reason", TypeRef.STRING)); - System.out.println("Error's payload size: " + exception.getPayload().length); + System.out.println("Error payload size: " + exception.getPayload().length); } } System.out.println("Done"); diff --git a/examples/src/main/java/io/dapr/examples/exception/README.md b/examples/src/main/java/io/dapr/examples/exception/README.md index 0776f614b..721817368 100644 --- a/examples/src/main/java/io/dapr/examples/exception/README.md +++ b/examples/src/main/java/io/dapr/examples/exception/README.md @@ -67,7 +67,7 @@ expected_stdout_lines: - '== APP == Error code: INVALID_ARGUMENT' - '== APP == Error message: INVALID_ARGUMENT: pubsub unknown_pubsub is not found' - '== APP == Reason: DAPR_PUBSUB_NOT_FOUND' - - '== APP == Error's payload size: 116' + - '== APP == Error payload size: 116' background: true sleep: 5 --> @@ -87,7 +87,7 @@ Once running, the State Client Example should print the output as follows: == APP == Reason: DAPR_PUBSUB_NOT_FOUND -== APP == Error's payload size: 116 +== APP == Error payload size: 116 ... ``` From c5d3cf3898f2903f97c3a2a6c23e9fc15c5cf662 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Thu, 15 Feb 2024 09:01:58 -0800 Subject: [PATCH 4/5] Lint. Signed-off-by: Artur Souza --- sdk/src/main/java/io/dapr/client/DaprHttp.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 08c9cc670..ed2b7e996 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -17,7 +17,6 @@ import io.dapr.client.domain.Metadata; import io.dapr.config.Properties; import io.dapr.exceptions.DaprError; -import io.dapr.exceptions.DaprErrorDetails; import io.dapr.exceptions.DaprException; import io.dapr.utils.Version; import okhttp3.Call; @@ -350,7 +349,7 @@ private static DaprError parseDaprError(byte[] json) { try { return DAPR_ERROR_DETAILS_OBJECT_MAPPER.readValue(json, DaprError.class); } catch (IOException e) { - throw new DaprException("UNKNOWN", new String(json), json); + throw new DaprException("UNKNOWN", new String(json, StandardCharsets.UTF_8), json); } } From b7cc6c97dc75d16f0e61191825302730f694d9b8 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Thu, 15 Feb 2024 09:27:38 -0800 Subject: [PATCH 5/5] Fix test. Signed-off-by: Artur Souza --- sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index a780bfdb9..34ec5396a 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -387,7 +387,7 @@ public void invokeServiceDaprErrorUnknownJSON() { }); assertEquals("UNKNOWN", exception.getErrorCode()); - assertEquals("UNKNOWN: Could not parse error's payload.", exception.getMessage()); + assertEquals("UNKNOWN: { \"anything\": 7 }", exception.getMessage()); assertEquals("{ \"anything\": 7 }", new String(exception.getPayload())); }