Skip to content

Commit 31ec0e7

Browse files
authored
Modify SDK to not fail on invalid Expires header (#5056)
* Add Warnings in the async client interface and CrtClient against passing in Runnable::run * Update warning message * Updated warning message * Added paragraph notation * Add a paragraph notation * Modify S3 expires field to not fail on parsing errors and instead, log warnings. Also modified the Expires field to be a timestamp * Fix checkstyle issues * Fixed duplicates in customization.config definition * Remove duplicate definitions * Facilitate custom handling of data type conversion errors * Removed test class * Remove incorrectly added statements * Added Unit tests * Changed to Junit5 * Fixed checkstyle issues * Added wiremock * assertThat instead of assertTrue and logged the entire exception stack * modified error message
1 parent e74fa31 commit 31ec0e7

File tree

12 files changed

+313
-7
lines changed

12 files changed

+313
-7
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/ShapeModifiersProcessor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ private void postprocessModifyMemberProperty(ShapeModel shapeModel, String membe
160160
.getUnmarshallLocationName());
161161
}
162162

163+
if (modifyModel.isIgnoreDataTypeConversionFailures()) {
164+
MemberModel memberModel = shapeModel.findMemberModelByC2jName(memberName);
165+
memberModel.ignoreDataTypeConversionFailures(true);
166+
}
167+
163168
}
164169

165170
/**

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/ModifyModelShapeModifier.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ public class ModifyModelShapeModifier {
5959

6060
private String unmarshallLocationName;
6161

62+
/**
63+
* Indicates whether data type conversion failures are to be ignored
64+
*/
65+
private boolean ignoreDataTypeConversionFailures;
66+
6267
public String getDeprecatedMessage() {
6368
return deprecatedMessage;
6469
}
@@ -130,4 +135,12 @@ public String getEmitAsType() {
130135
public void setEmitAsType(String emitAsType) {
131136
this.emitAsType = emitAsType;
132137
}
138+
139+
public void setIgnoreDataTypeConversionFailures(boolean ignoreDataTypeConversionFailures) {
140+
this.ignoreDataTypeConversionFailures = ignoreDataTypeConversionFailures;
141+
}
142+
143+
public boolean isIgnoreDataTypeConversionFailures() {
144+
return ignoreDataTypeConversionFailures;
145+
}
133146
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ public class MemberModel extends DocumentationModel {
115115

116116
private ContextParam contextParam;
117117

118+
private boolean ignoreDataTypeConversionFailures;
119+
118120
public String getName() {
119121
return name;
120122
}
@@ -775,4 +777,12 @@ public ContextParam getContextParam() {
775777
public void setContextParam(ContextParam contextParam) {
776778
this.contextParam = contextParam;
777779
}
780+
781+
public void ignoreDataTypeConversionFailures(boolean ignoreDataTypeConversionFailures) {
782+
this.ignoreDataTypeConversionFailures = ignoreDataTypeConversionFailures;
783+
}
784+
785+
public boolean ignoreDataTypeConversionFailures() {
786+
return ignoreDataTypeConversionFailures;
787+
}
778788
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import software.amazon.awssdk.core.SdkField;
4040
import software.amazon.awssdk.core.protocol.MarshallLocation;
4141
import software.amazon.awssdk.core.protocol.MarshallingType;
42+
import software.amazon.awssdk.core.traits.DataTypeConversionFailureHandlingTrait;
4243
import software.amazon.awssdk.core.traits.DefaultValueTrait;
4344
import software.amazon.awssdk.core.traits.JsonValueTrait;
4445
import software.amazon.awssdk.core.traits.ListTrait;
@@ -186,6 +187,10 @@ private CodeBlock traits(MemberModel m) {
186187
if (m.isXmlAttribute()) {
187188
traits.add(createXmlAttributeTrait());
188189
}
190+
191+
if (m.ignoreDataTypeConversionFailures()) {
192+
traits.add(createDataTypeConversionFailureHandlingTrait());
193+
}
189194
if (customizationConfig.isRequiredTraitValidationEnabled() && m.isRequired()) {
190195
traits.add(createRequiredTrait());
191196
}
@@ -206,6 +211,12 @@ private boolean attachPayloadTraitToMember(MemberModel m) {
206211
.equals(m.getC2jName());
207212
}
208213

214+
private CodeBlock createDataTypeConversionFailureHandlingTrait() {
215+
return CodeBlock.builder()
216+
.add("new $T()", ClassName.get(DataTypeConversionFailureHandlingTrait.class))
217+
.build();
218+
}
219+
209220
private CodeBlock createTimestampFormatTrait(MemberModel m) {
210221
TimestampFormatTrait.Format format = TimestampFormatTrait.Format.fromString(m.getTimestampFormat());
211222
ClassName traitClass = ClassName.get(TimestampFormatTrait.class);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/customization.config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
"deprecated": true,
2727
"deprecatedMessage": "This field is modified as deprecated."
2828
}
29+
},
30+
{
31+
"MemberIgnoreDataTypeFailureHandling": {
32+
"ignoreDataTypeConversionFailures": "true"
33+
}
2934
}
3035
]
3136
},

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

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import software.amazon.awssdk.core.SdkPojo;
1515
import software.amazon.awssdk.core.protocol.MarshallLocation;
1616
import software.amazon.awssdk.core.protocol.MarshallingType;
17+
import software.amazon.awssdk.core.traits.DataTypeConversionFailureHandlingTrait;
1718
import software.amazon.awssdk.core.traits.LocationTrait;
1819
import software.amazon.awssdk.utils.ToString;
1920
import software.amazon.awssdk.utils.builder.CopyableBuilder;
@@ -45,20 +46,33 @@ public final class OperationWithDeprecatedMemberRequest extends JsonProtocolTest
4546
.traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("UndeprecatedMember").build())
4647
.build();
4748

49+
private static final SdkField<String> MEMBER_IGNORE_DATA_TYPE_FAILURE_HANDLING_FIELD = SdkField
50+
.<String> builder(MarshallingType.STRING)
51+
.memberName("MemberIgnoreDataTypeFailureHandling")
52+
.getter(getter(OperationWithDeprecatedMemberRequest::memberIgnoreDataTypeFailureHandling))
53+
.setter(setter(Builder::memberIgnoreDataTypeFailureHandling))
54+
.traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD)
55+
.locationName("MemberIgnoreDataTypeFailureHandling").build(), new DataTypeConversionFailureHandlingTrait())
56+
.build();
57+
4858
private static final List<SdkField<?>> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(
49-
MEMBER_MODELED_AS_DEPRECATED_FIELD, MEMBER_MODIFIED_AS_DEPRECATED_FIELD, UNDEPRECATED_MEMBER_FIELD));
59+
MEMBER_MODELED_AS_DEPRECATED_FIELD, MEMBER_MODIFIED_AS_DEPRECATED_FIELD, UNDEPRECATED_MEMBER_FIELD,
60+
MEMBER_IGNORE_DATA_TYPE_FAILURE_HANDLING_FIELD));
5061

5162
private final String memberModeledAsDeprecated;
5263

5364
private final String memberModifiedAsDeprecated;
5465

5566
private final String undeprecatedMember;
5667

68+
private final String memberIgnoreDataTypeFailureHandling;
69+
5770
private OperationWithDeprecatedMemberRequest(BuilderImpl builder) {
5871
super(builder);
5972
this.memberModeledAsDeprecated = builder.memberModeledAsDeprecated;
6073
this.memberModifiedAsDeprecated = builder.memberModifiedAsDeprecated;
6174
this.undeprecatedMember = builder.undeprecatedMember;
75+
this.memberIgnoreDataTypeFailureHandling = builder.memberIgnoreDataTypeFailureHandling;
6276
}
6377

6478
/**
@@ -92,6 +106,15 @@ public final String undeprecatedMember() {
92106
return undeprecatedMember;
93107
}
94108

109+
/**
110+
* Returns the value of the MemberIgnoreDataTypeFailureHandling property for this object.
111+
*
112+
* @return The value of the MemberIgnoreDataTypeFailureHandling property for this object.
113+
*/
114+
public final String memberIgnoreDataTypeFailureHandling() {
115+
return memberIgnoreDataTypeFailureHandling;
116+
}
117+
95118
@Override
96119
public Builder toBuilder() {
97120
return new BuilderImpl(this);
@@ -112,6 +135,7 @@ public final int hashCode() {
112135
hashCode = 31 * hashCode + Objects.hashCode(memberModeledAsDeprecated());
113136
hashCode = 31 * hashCode + Objects.hashCode(memberModifiedAsDeprecated());
114137
hashCode = 31 * hashCode + Objects.hashCode(undeprecatedMember());
138+
hashCode = 31 * hashCode + Objects.hashCode(memberIgnoreDataTypeFailureHandling());
115139
return hashCode;
116140
}
117141

@@ -134,7 +158,8 @@ public final boolean equalsBySdkFields(Object obj) {
134158
OperationWithDeprecatedMemberRequest other = (OperationWithDeprecatedMemberRequest) obj;
135159
return Objects.equals(memberModeledAsDeprecated(), other.memberModeledAsDeprecated())
136160
&& Objects.equals(memberModifiedAsDeprecated(), other.memberModifiedAsDeprecated())
137-
&& Objects.equals(undeprecatedMember(), other.undeprecatedMember());
161+
&& Objects.equals(undeprecatedMember(), other.undeprecatedMember())
162+
&& Objects.equals(memberIgnoreDataTypeFailureHandling(), other.memberIgnoreDataTypeFailureHandling());
138163
}
139164

140165
/**
@@ -146,7 +171,7 @@ public final String toString() {
146171
return ToString.builder("OperationWithDeprecatedMemberRequest")
147172
.add("MemberModeledAsDeprecated", memberModeledAsDeprecated())
148173
.add("MemberModifiedAsDeprecated", memberModifiedAsDeprecated()).add("UndeprecatedMember", undeprecatedMember())
149-
.build();
174+
.add("MemberIgnoreDataTypeFailureHandling", memberIgnoreDataTypeFailureHandling()).build();
150175
}
151176

152177
public final <T> Optional<T> getValueForField(String fieldName, Class<T> clazz) {
@@ -157,6 +182,8 @@ public final <T> Optional<T> getValueForField(String fieldName, Class<T> clazz)
157182
return Optional.ofNullable(clazz.cast(memberModifiedAsDeprecated()));
158183
case "UndeprecatedMember":
159184
return Optional.ofNullable(clazz.cast(undeprecatedMember()));
185+
case "MemberIgnoreDataTypeFailureHandling":
186+
return Optional.ofNullable(clazz.cast(memberIgnoreDataTypeFailureHandling()));
160187
default:
161188
return Optional.empty();
162189
}
@@ -208,6 +235,15 @@ public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo,
208235
*/
209236
Builder undeprecatedMember(String undeprecatedMember);
210237

238+
/**
239+
* Sets the value of the MemberIgnoreDataTypeFailureHandling property for this object.
240+
*
241+
* @param memberIgnoreDataTypeFailureHandling
242+
* The new value for the MemberIgnoreDataTypeFailureHandling property for this object.
243+
* @return Returns a reference to this object so that method calls can be chained together.
244+
*/
245+
Builder memberIgnoreDataTypeFailureHandling(String memberIgnoreDataTypeFailureHandling);
246+
211247
@Override
212248
Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration);
213249

@@ -222,6 +258,8 @@ static final class BuilderImpl extends JsonProtocolTestsRequest.BuilderImpl impl
222258

223259
private String undeprecatedMember;
224260

261+
private String memberIgnoreDataTypeFailureHandling;
262+
225263
private BuilderImpl() {
226264
}
227265

@@ -230,6 +268,7 @@ private BuilderImpl(OperationWithDeprecatedMemberRequest model) {
230268
memberModeledAsDeprecated(model.memberModeledAsDeprecated);
231269
memberModifiedAsDeprecated(model.memberModifiedAsDeprecated);
232270
undeprecatedMember(model.undeprecatedMember);
271+
memberIgnoreDataTypeFailureHandling(model.memberIgnoreDataTypeFailureHandling);
233272
}
234273

235274
@Deprecated
@@ -280,6 +319,20 @@ public final Builder undeprecatedMember(String undeprecatedMember) {
280319
return this;
281320
}
282321

322+
public final String getMemberIgnoreDataTypeFailureHandling() {
323+
return memberIgnoreDataTypeFailureHandling;
324+
}
325+
326+
public final void setMemberIgnoreDataTypeFailureHandling(String memberIgnoreDataTypeFailureHandling) {
327+
this.memberIgnoreDataTypeFailureHandling = memberIgnoreDataTypeFailureHandling;
328+
}
329+
330+
@Override
331+
public final Builder memberIgnoreDataTypeFailureHandling(String memberIgnoreDataTypeFailureHandling) {
332+
this.memberIgnoreDataTypeFailureHandling = memberIgnoreDataTypeFailureHandling;
333+
return this;
334+
}
335+
283336
@Override
284337
public Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration) {
285338
super.overrideConfiguration(overrideConfiguration);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/service-2.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@
247247
"deprecatedMessage": "This field is modeled as deprecated."
248248
},
249249
"MemberModifiedAsDeprecated":{"shape": "String"},
250-
"UndeprecatedMember": {"shape": "String"}
250+
"UndeprecatedMember": {"shape": "String"},
251+
"MemberIgnoreDataTypeFailureHandling":{"shape": "String"}
251252
}
252253
},
253254
"OperationWithDeprecatedMemberResponse":{

core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/HeaderUnmarshaller.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import software.amazon.awssdk.core.SdkField;
2727
import software.amazon.awssdk.protocols.core.StringToValueConverter;
2828
import software.amazon.awssdk.protocols.query.unmarshall.XmlElement;
29+
import software.amazon.awssdk.utils.Logger;
2930

3031
@SdkInternalApi
3132
public final class HeaderUnmarshaller {
@@ -60,6 +61,7 @@ private HeaderUnmarshaller() {
6061
}
6162

6263
private static class SimpleHeaderUnmarshaller<T> implements XmlUnmarshaller<T> {
64+
private static final Logger log = Logger.loggerFor(SimpleHeaderUnmarshaller.class);
6365

6466
private final StringToValueConverter.StringToValue<T> stringToValue;
6567

@@ -69,9 +71,17 @@ private SimpleHeaderUnmarshaller(StringToValueConverter.StringToValue<T> stringT
6971

7072
@Override
7173
public T unmarshall(XmlUnmarshallerContext context, List<XmlElement> content, SdkField<T> field) {
72-
return context.response().firstMatchingHeader(field.locationName())
73-
.map(s -> stringToValue.convert(s, field))
74-
.orElse(null);
74+
try {
75+
return context.response().firstMatchingHeader(field.locationName())
76+
.map(s -> stringToValue.convert(s, field))
77+
.orElse(null);
78+
} catch (RuntimeException e) {
79+
log.warn(() -> "Exception found while parsing response header " , e);
80+
if (field.ignoreDataTypeConversionFailures()) {
81+
return null;
82+
}
83+
throw e;
84+
}
7585
}
7686
}
7787
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkField.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import software.amazon.awssdk.annotations.SdkProtectedApi;
2626
import software.amazon.awssdk.core.protocol.MarshallLocation;
2727
import software.amazon.awssdk.core.protocol.MarshallingType;
28+
import software.amazon.awssdk.core.traits.DataTypeConversionFailureHandlingTrait;
2829
import software.amazon.awssdk.core.traits.DefaultValueTrait;
2930
import software.amazon.awssdk.core.traits.LocationTrait;
3031
import software.amazon.awssdk.core.traits.Trait;
@@ -86,6 +87,16 @@ public String locationName() {
8687
return locationName;
8788
}
8889

90+
/**
91+
* @return whether data-type conversion errors are to be ignored
92+
*/
93+
public boolean ignoreDataTypeConversionFailures() {
94+
DataTypeConversionFailureHandlingTrait dataTypeConversionFailureHandlingTrait =
95+
getTrait(DataTypeConversionFailureHandlingTrait.class);
96+
97+
return dataTypeConversionFailureHandlingTrait != null;
98+
}
99+
89100
/**
90101
* @return The location name to use when unmarshalling. This is only needed for AWS/Query or EC2 services. All
91102
* other services should use {@link #locationName} for both marshalling and unmarshalling.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.core.traits;
17+
18+
import software.amazon.awssdk.annotations.SdkProtectedApi;
19+
20+
@SdkProtectedApi
21+
public class DataTypeConversionFailureHandlingTrait implements Trait {
22+
}

0 commit comments

Comments
 (0)