Skip to content

Commit f1e0f55

Browse files
authored
Add customization in S3 to keep expires as timestamp type (#5610)
1 parent 6ad9084 commit f1e0f55

File tree

7 files changed

+184
-40
lines changed

7 files changed

+184
-40
lines changed

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import software.amazon.awssdk.codegen.model.service.Operation;
3232
import software.amazon.awssdk.codegen.model.service.ServiceModel;
3333
import software.amazon.awssdk.codegen.model.service.Shape;
34+
import software.amazon.awssdk.utils.CollectionUtils;
35+
import software.amazon.awssdk.utils.Validate;
3436

3537
/**
3638
* This processor internally keeps track of all the structure members whose
@@ -53,6 +55,8 @@ final class ShapeSubstitutionsProcessor implements CodegenCustomizationProcessor
5355
*/
5456
private final Map<String, Map<String, String>> substitutedListMemberReferences = new HashMap<>();
5557

58+
private final Map<String, Shape> newShapesToAdd = new HashMap<>();
59+
5660
ShapeSubstitutionsProcessor(
5761
Map<String, ShapeSubstitution> shapeSubstitutions) {
5862
this.shapeSubstitutions = shapeSubstitutions;
@@ -66,12 +70,15 @@ public void preprocess(ServiceModel serviceModel) {
6670
}
6771

6872
// Make sure the substituted shapes exist in the service model
69-
for (String substitutedShape : shapeSubstitutions.keySet()) {
70-
if (!serviceModel.getShapes().containsKey(substitutedShape)) {
73+
for (Entry<String, ShapeSubstitution> substitutedShapeEntry : shapeSubstitutions.entrySet()) {
74+
if (!serviceModel.getShapes().containsKey(substitutedShapeEntry.getKey())) {
7175
throw new IllegalStateException(
72-
"shapeSubstitution customization found for shape "
73-
+ substitutedShape + ", which does not exist in the service model.");
76+
"shapeSubstitution customization found for shape "
77+
+ substitutedShapeEntry + ", which does not exist in the service model.");
7478
}
79+
ShapeSubstitution shapeSubstitution = substitutedShapeEntry.getValue();
80+
Validate.mutuallyExclusive("emitAsShape and emitAsType are mutually exclusive",
81+
shapeSubstitution.getEmitAsShape(), shapeSubstitution.getEmitAsType());
7582
}
7683

7784
// Make sure the substituted shapes are not referenced by any operation
@@ -84,9 +91,12 @@ public void preprocess(ServiceModel serviceModel) {
8491
for (Entry<String, Shape> entry : serviceModel.getShapes().entrySet()) {
8592
String shapeName = entry.getKey();
8693
Shape shape = entry.getValue();
87-
8894
preprocessSubstituteShapeReferencesInShape(shapeName, shape, serviceModel);
8995
}
96+
97+
if (!CollectionUtils.isNullOrEmpty(newShapesToAdd)) {
98+
serviceModel.getShapes().putAll(newShapesToAdd);
99+
}
90100
}
91101

92102
@Override
@@ -209,8 +219,24 @@ private void preprocessSubstituteShapeReferencesInShape(
209219
private ShapeSubstitution substituteMemberShape(Member member) {
210220
ShapeSubstitution substitute = shapeSubstitutions.get(member.getShape());
211221

212-
if (substitute != null) {
213-
member.setShape(substitute.getEmitAsShape());
222+
if (substitute == null) {
223+
return null;
224+
}
225+
226+
String emitAsShape = substitute.getEmitAsShape();
227+
if (emitAsShape != null) {
228+
member.setShape(emitAsShape);
229+
return substitute;
230+
}
231+
232+
String emitAsType = substitute.getEmitAsType();
233+
234+
if (emitAsType != null) {
235+
Shape newShapeForType = new Shape();
236+
newShapeForType.setType(emitAsType);
237+
String shapeName = "SdkCustomization_" + emitAsType;
238+
member.setShape(shapeName);
239+
newShapesToAdd.put(shapeName, newShapeForType);
214240
return substitute;
215241
}
216242

codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ public static boolean isStructure(Shape shape) {
5757
}
5858

5959
public static boolean isListShape(Shape shape) {
60-
return shape.getType().equals("list");
60+
return shape != null && shape.getType() != null && shape.getType().equals("list");
6161
}
6262

6363
public static boolean isMapShape(Shape shape) {
64-
return shape.getType().equals("map");
64+
return shape.getType() != null && shape.getType().equals("map");
6565
}
6666

6767
public static boolean isEnumShape(Shape shape) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
public class ShapeSubstitution {
2929

3030
private String emitAsShape;
31+
private String emitAsType;
3132
private String emitFromMember;
3233

3334
/**
@@ -54,6 +55,14 @@ public String getEmitFromMember() {
5455
return emitFromMember;
5556
}
5657

58+
public String getEmitAsType() {
59+
return emitAsType;
60+
}
61+
62+
public void setEmitAsType(String emitAsType) {
63+
this.emitAsType = emitAsType;
64+
}
65+
5766
public void setEmitFromMember(String emitFromMember) {
5867
this.emitFromMember = emitFromMember;
5968
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.codegen.customization.processors;
17+
18+
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
19+
20+
import java.io.File;
21+
import java.io.IOException;
22+
import org.junit.jupiter.api.BeforeAll;
23+
import org.junit.jupiter.api.Test;
24+
import software.amazon.awssdk.codegen.C2jModels;
25+
import software.amazon.awssdk.codegen.IntermediateModelBuilder;
26+
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
27+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
28+
import software.amazon.awssdk.codegen.model.service.ServiceModel;
29+
import software.amazon.awssdk.codegen.model.service.Shape;
30+
import software.amazon.awssdk.codegen.utils.ModelLoaderUtils;
31+
32+
public class ShapeSubstitutionsProcessorTest {
33+
34+
private static CustomizationConfig config;
35+
private static ServiceModel serviceModel;
36+
37+
@BeforeAll
38+
public static void setUp() throws IOException {
39+
File serviceModelFile = new File(ShapeSubstitutionsProcessorTest.class.getResource("service-2.json").getFile());
40+
serviceModel = ModelLoaderUtils.loadModel(ServiceModel.class, serviceModelFile);
41+
File customizationConfigFile = new File(ShapeSubstitutionsProcessorTest.class.getResource("customization.config").getFile());
42+
serviceModel = ModelLoaderUtils.loadModel(ServiceModel.class, serviceModelFile);
43+
config = ModelLoaderUtils.loadModel(CustomizationConfig.class, customizationConfigFile);
44+
}
45+
46+
@Test
47+
public void setCustomStringShape_isAddedToModel() {
48+
assertThat(serviceModel.getShapes().get("Timestamp").getType()).isEqualTo("string");
49+
IntermediateModel intermediateModel = new IntermediateModelBuilder(C2jModels.builder()
50+
.serviceModel(serviceModel)
51+
.customizationConfig(config)
52+
.build())
53+
.build();
54+
55+
assertThat(serviceModel.getShapes().get("AllTypesStructure").getMembers().get("Timestamp").getShape()).isEqualTo(
56+
"SdkCustomization_timestamp");
57+
Shape listShape = serviceModel.getShapes().get("ListOfTimestamps");
58+
assertThat(listShape.getListMember().getShape()).isEqualTo("SdkCustomization_timestamp");
59+
60+
Shape structShape = serviceModel.getShapes().get("StructWithTimestamp");
61+
assertThat(structShape.getMembers().get("Timestamp").getShape()).isEqualTo("SdkCustomization_timestamp");
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"shapeSubstitutions": {
3+
"Timestamp": {
4+
"emitAsType": "timestamp"
5+
}
6+
}
7+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"version":"2.0",
3+
"metadata":{
4+
"apiVersion":"2016-03-11",
5+
"endpointPrefix":"restjson",
6+
"jsonVersion":"1.1",
7+
"protocol":"rest-json",
8+
"serviceAbbreviation":"JsonProtocolTests",
9+
"serviceFullName":"AWS DR Tools JSON Protocol Tests",
10+
"serviceId":"Json Protocol Tests",
11+
"signatureVersion":"v4",
12+
"targetPrefix":"ProtocolTestsJsonRpcService",
13+
"timestampFormat":"unixTimestamp",
14+
"uid":"restjson-2016-03-11"
15+
},
16+
"operations":{
17+
"AllTypes":{
18+
"name":"AllTypes",
19+
"http":{
20+
"method":"POST",
21+
"requestUri":"/"
22+
},
23+
"input":{"shape":"AllTypesStructure"}
24+
}
25+
},
26+
"shapes": {
27+
"AllTypesStructure": {
28+
"type": "structure",
29+
"members": {
30+
"TimeStampMember": {
31+
"shape": "Timestamp"
32+
},
33+
"ListOfTimestamps": {
34+
"shape": "ListOfTimestamps"
35+
},
36+
"Timestamp": {
37+
"shape": "Timestamp"
38+
},
39+
"StructWithTimestamp": {
40+
"shape": "StructWithTimestamp"
41+
}
42+
}
43+
},
44+
"ListOfTimestamps": {
45+
"type": "list",
46+
"member": {
47+
"shape": "Timestamp"
48+
}
49+
},
50+
"StructWithTimestamp": {
51+
"type": "structure",
52+
"members": {
53+
"Timestamp": {
54+
"shape": "Timestamp"
55+
}
56+
}
57+
},
58+
"Timestamp": {
59+
"type": "string"
60+
},
61+
"String" : {
62+
"type" : "string"
63+
}
64+
}
65+
}

services/s3/src/main/resources/codegen-resources/customization.config

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
{
2+
"shapeSubstitutions": {
3+
"Expires": {
4+
"emitAsType": "timestamp"
5+
}
6+
},
27
"verifiedSimpleMethods": [
38
"listBuckets"
49
],
@@ -27,24 +32,6 @@
2732
}
2833
]
2934
},
30-
"PutObjectRequest": {
31-
"modify": [
32-
{
33-
"Expires": {
34-
"emitAsType": "timestamp"
35-
}
36-
}
37-
]
38-
},
39-
"WriteGetObjectResponseRequest": {
40-
"modify": [
41-
{
42-
"Expires": {
43-
"emitAsType": "timestamp"
44-
}
45-
}
46-
]
47-
},
4835
"GetObjectOutput": {
4936
"modify": [
5037
{
@@ -89,15 +76,6 @@
8976
}
9077
]
9178
},
92-
"CreateMultipartUploadRequest": {
93-
"modify": [
94-
{
95-
"Expires": {
96-
"emitAsType": "timestamp"
97-
}
98-
}
99-
]
100-
},
10179
"UploadPartRequest": {
10280
"inject": [
10381
{
@@ -138,11 +116,7 @@
138116
"Key": {
139117
"emitPropertyName": "DestinationKey",
140118
"existingNameDeprecated": true
141-
},
142-
"Expires": {
143-
"emitAsType": "timestamp"
144119
}
145-
146120
}
147121
]
148122
},

0 commit comments

Comments
 (0)