Skip to content

Commit f14f4a2

Browse files
authored
Include retried failure messages as "suppressed" exceptions. (#3560)
Additionally, always include a useful exception message even when the service returns no error message. Stack trace example before this change: ``` software.amazon.awssdk.services.protocolrestjson.model.ProtocolRestJsonException: null (Service: ProtocolRestJson, Status Code: 400, Request ID: null) at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handleErrorResponse(CombinedResponseHandler.java:125) ... at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) ``` Stack trace example after this change: ``` software.amazon.awssdk.services.protocolrestjson.model.ProtocolRestJsonException: Service returned HTTP status code 400 (Service: ProtocolRestJson, Status Code: 400, Request ID: null) at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handleErrorResponse(CombinedResponseHandler.java:125) ... at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 1 failure: Service returned HTTP status code 500 (Service: ProtocolRestJson, Status Code: 500, Request ID: null) Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 2 failure: Service returned HTTP status code 500 (Service: ProtocolRestJson, Status Code: 500, Request ID: null) ```
1 parent de3f73d commit f14f4a2

File tree

25 files changed

+385
-20
lines changed

25 files changed

+385
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"contributor": "",
4+
"type": "feature",
5+
"description": "When raising an exception as a result of a service response, if service does not return a error message, include the error code or HTTP status code in exception messages instead of the string \"null\"."
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"contributor": "",
4+
"type": "feature",
5+
"description": "When a request fails after SDK retries, include the retried failure messages as \"suppressed\" exceptions. Stack traces for these suppressed exceptions are not preserved."
6+
}

.idea/inspectionProfiles/AWS_Java_SDK_2_0.xml

+4-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ExceptionProperties.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public static List<MethodSpec> builderInterfaceMethods(ClassName className) {
3333
builderMethod(className, "message", String.class),
3434
builderMethod(className, "requestId", String.class),
3535
builderMethod(className, "statusCode", int.class),
36-
builderMethod(className, "cause", Throwable.class));
36+
builderMethod(className, "cause", Throwable.class),
37+
builderMethod(className, "writableStackTrace", Boolean.class));
3738
}
3839

3940
public static List<MethodSpec> builderImplMethods(ClassName className) {
@@ -42,7 +43,8 @@ public static List<MethodSpec> builderImplMethods(ClassName className) {
4243
builderImplMethods(className, "message", String.class),
4344
builderImplMethods(className, "requestId", String.class),
4445
builderImplMethods(className, "statusCode", int.class),
45-
builderImplMethods(className, "cause", Throwable.class));
46+
builderImplMethods(className, "cause", Throwable.class),
47+
builderImplMethods(className, "writableStackTrace", Boolean.class));
4648
}
4749

4850
private static MethodSpec builderMethod(ClassName className, String name, Class clazz) {

codegen/src/main/resources/software/amazon/awssdk/codegen/rules/SourceException.java.resource

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public class SourceException extends SdkException {
1515
@Override
1616
Builder cause(Throwable cause);
1717

18+
@Override
19+
Builder writableStackTrace(Boolean writableStackTrace);
20+
1821
@Override
1922
Builder message(String message);
2023

@@ -35,6 +38,12 @@ public class SourceException extends SdkException {
3538
return this;
3639
}
3740

41+
@Override
42+
public Builder writableStackTrace(Boolean writableStackTrace) {
43+
super.writableStackTrace(writableStackTrace);
44+
return this;
45+
}
46+
3847
@Override
3948
public SourceException build() {
4049
return new SourceException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/baseserviceexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public interface Builder extends AwsServiceException.Builder {
3737

3838
@Override
3939
Builder cause(Throwable cause);
40+
41+
@Override
42+
Builder writableStackTrace(Boolean writableStackTrace);
4043
}
4144

4245
protected static class BuilderImpl extends AwsServiceException.BuilderImpl implements Builder {
@@ -77,6 +80,12 @@ public BuilderImpl cause(Throwable cause) {
7780
return this;
7881
}
7982

83+
@Override
84+
public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
85+
this.writableStackTrace = writableStackTrace;
86+
return this;
87+
}
88+
8089
@Override
8190
public JsonProtocolTestsException build() {
8291
return new JsonProtocolTestsException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/emptymodeledexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public interface Builder extends SdkPojo, CopyableBuilder<Builder, EmptyModeledE
5656

5757
@Override
5858
Builder cause(Throwable cause);
59+
60+
@Override
61+
Builder writableStackTrace(Boolean writableStackTrace);
5962
}
6063

6164
static final class BuilderImpl extends JsonProtocolTestsException.BuilderImpl implements Builder {
@@ -96,6 +99,12 @@ public BuilderImpl cause(Throwable cause) {
9699
return this;
97100
}
98101

102+
@Override
103+
public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
104+
this.writableStackTrace = writableStackTrace;
105+
return this;
106+
}
107+
99108
@Override
100109
public EmptyModeledException build() {
101110
return new EmptyModeledException(this);

core/aws-core/src/main/java/software/amazon/awssdk/awscore/exception/AwsServiceException.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ public String getMessage() {
7070
if (extendedRequestId() != null) {
7171
details.add("Extended Request ID: " + extendedRequestId());
7272
}
73-
return awsErrorDetails().errorMessage() + " " + details;
73+
String message = super.getMessage();
74+
if (message == null) {
75+
message = awsErrorDetails().errorMessage();
76+
}
77+
return message + " " + details;
7478
}
7579

7680
return super.getMessage();
@@ -234,6 +238,12 @@ public Builder cause(Throwable cause) {
234238
return this;
235239
}
236240

241+
@Override
242+
public Builder writableStackTrace(Boolean writableStackTrace) {
243+
this.writableStackTrace = writableStackTrace;
244+
return this;
245+
}
246+
237247
@Override
238248
public Builder requestId(String requestId) {
239249
this.requestId = requestId;

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/AwsJsonProtocolErrorUnmarshaller.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import software.amazon.awssdk.protocols.json.ErrorCodeParser;
3333
import software.amazon.awssdk.protocols.json.JsonContent;
3434
import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory;
35+
import software.amazon.awssdk.utils.StringUtils;
3536

3637
/**
3738
* Unmarshaller for AWS specific error responses. All errors are unmarshalled into a subtype of
@@ -80,13 +81,25 @@ private AwsServiceException unmarshall(SdkHttpFullResponse response, ExecutionAt
8081
errorCode, errorMessage));
8182
exception.clockSkew(getClockSkew(executionAttributes));
8283
// Status code and request id are sdk level fields
83-
exception.message(errorMessage);
84+
exception.message(errorMessageForException(errorMessage, errorCode, response.statusCode()));
8485
exception.statusCode(statusCode(response, modeledExceptionMetadata));
8586
exception.requestId(response.firstMatchingHeader(X_AMZN_REQUEST_ID_HEADERS).orElse(null));
8687
exception.extendedRequestId(response.firstMatchingHeader(X_AMZ_ID_2_HEADER).orElse(null));
8788
return exception.build();
8889
}
8990

91+
private String errorMessageForException(String errorMessage, String errorCode, int statusCode) {
92+
if (StringUtils.isNotBlank(errorMessage)) {
93+
return errorMessage;
94+
}
95+
96+
if (StringUtils.isNotBlank(errorCode)) {
97+
return "Service returned error code " + errorCode;
98+
}
99+
100+
return "Service returned HTTP status code " + statusCode;
101+
}
102+
90103
private Duration getClockSkew(ExecutionAttributes executionAttributes) {
91104
Integer timeOffset = executionAttributes.getAttribute(SdkExecutionAttribute.TIME_OFFSET);
92105
return timeOffset == null ? null : Duration.ofSeconds(timeOffset);

core/sdk-core/src/main/java/software/amazon/awssdk/core/endpointdiscovery/EndpointDiscoveryFailedException.java

+9
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public interface Builder extends SdkClientException.Builder {
5555
@Override
5656
Builder cause(Throwable cause);
5757

58+
@Override
59+
Builder writableStackTrace(Boolean writableStackTrace);
60+
5861
@Override
5962
EndpointDiscoveryFailedException build();
6063
}
@@ -80,6 +83,12 @@ public Builder cause(Throwable cause) {
8083
return this;
8184
}
8285

86+
@Override
87+
public Builder writableStackTrace(Boolean writableStackTrace) {
88+
this.writableStackTrace = writableStackTrace;
89+
return this;
90+
}
91+
8392
@Override
8493
public EndpointDiscoveryFailedException build() {
8594
return new EndpointDiscoveryFailedException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/AbortedException.java

+9
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public interface Builder extends SdkClientException.Builder {
5454
@Override
5555
Builder cause(Throwable cause);
5656

57+
@Override
58+
Builder writableStackTrace(Boolean writableStackTrace);
59+
5760
@Override
5861
AbortedException build();
5962
}
@@ -79,6 +82,12 @@ public Builder cause(Throwable cause) {
7982
return this;
8083
}
8184

85+
@Override
86+
public Builder writableStackTrace(Boolean writableStackTrace) {
87+
this.writableStackTrace = writableStackTrace;
88+
return this;
89+
}
90+
8291
@Override
8392
public AbortedException build() {
8493
return new AbortedException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/ApiCallAttemptTimeoutException.java

+9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public interface Builder extends SdkClientException.Builder {
5858
@Override
5959
Builder cause(Throwable cause);
6060

61+
@Override
62+
Builder writableStackTrace(Boolean writableStackTrace);
63+
6164
@Override
6265
ApiCallAttemptTimeoutException build();
6366
}
@@ -83,6 +86,12 @@ public Builder cause(Throwable cause) {
8386
return this;
8487
}
8588

89+
@Override
90+
public Builder writableStackTrace(Boolean writableStackTrace) {
91+
this.writableStackTrace = writableStackTrace;
92+
return this;
93+
}
94+
8695
@Override
8796
public ApiCallAttemptTimeoutException build() {
8897
return new ApiCallAttemptTimeoutException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/ApiCallTimeoutException.java

+9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public interface Builder extends SdkClientException.Builder {
5858
@Override
5959
Builder cause(Throwable cause);
6060

61+
@Override
62+
Builder writableStackTrace(Boolean writableStackTrace);
63+
6164
@Override
6265
ApiCallTimeoutException build();
6366
}
@@ -83,6 +86,12 @@ public Builder cause(Throwable cause) {
8386
return this;
8487
}
8588

89+
@Override
90+
public Builder writableStackTrace(Boolean writableStackTrace) {
91+
this.writableStackTrace = writableStackTrace;
92+
return this;
93+
}
94+
8695
@Override
8796
public ApiCallTimeoutException build() {
8897
return new ApiCallTimeoutException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/Crc32MismatchException.java

+9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public interface Builder extends SdkClientException.Builder {
5858
@Override
5959
Builder cause(Throwable cause);
6060

61+
@Override
62+
Builder writableStackTrace(Boolean writableStackTrace);
63+
6164
@Override
6265
Crc32MismatchException build();
6366
}
@@ -83,6 +86,12 @@ public Builder cause(Throwable cause) {
8386
return this;
8487
}
8588

89+
@Override
90+
public Builder writableStackTrace(Boolean writableStackTrace) {
91+
this.writableStackTrace = writableStackTrace;
92+
return this;
93+
}
94+
8695
@Override
8796
public Crc32MismatchException build() {
8897
return new Crc32MismatchException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/NonRetryableException.java

+9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public interface Builder extends SdkClientException.Builder {
5252
@Override
5353
Builder cause(Throwable cause);
5454

55+
@Override
56+
Builder writableStackTrace(Boolean writableStackTrace);
57+
5558
@Override
5659
NonRetryableException build();
5760
}
@@ -87,6 +90,12 @@ public Builder cause(Throwable cause) {
8790
return this;
8891
}
8992

93+
@Override
94+
public Builder writableStackTrace(Boolean writableStackTrace) {
95+
this.writableStackTrace = writableStackTrace;
96+
return this;
97+
}
98+
9099
@Override
91100
public NonRetryableException build() {
92101
return new NonRetryableException(this);

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/RetryableException.java

+9
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public interface Builder extends SdkClientException.Builder {
6060
@Override
6161
Builder cause(Throwable cause);
6262

63+
@Override
64+
Builder writableStackTrace(Boolean writableStackTrace);
65+
6366
@Override
6467
RetryableException build();
6568
}
@@ -85,6 +88,12 @@ public Builder cause(Throwable cause) {
8588
return this;
8689
}
8790

91+
@Override
92+
public Builder writableStackTrace(Boolean writableStackTrace) {
93+
this.writableStackTrace = writableStackTrace;
94+
return this;
95+
}
96+
8897
@Override
8998
public RetryableException build() {
9099
return new RetryableException(this);

0 commit comments

Comments
 (0)