Skip to content

Commit 7ec5558

Browse files
committed
Add support for ResponseMetadata
1 parent 8e4a913 commit 7ec5558

File tree

44 files changed

+1786
-242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1786
-242
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"type": "feature",
4+
"description": "Add `AwsResponseMetadata` support to allow users to retrieve metadata information such as `requestId`, `extendedRequestId` from the response. see [#670](https://github.com/aws/aws-sdk-java-v2/issues/670)"
5+
}

codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/ModelClassGeneratorTasks.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import software.amazon.awssdk.codegen.poet.model.AwsServiceBaseRequestSpec;
3232
import software.amazon.awssdk.codegen.poet.model.AwsServiceBaseResponseSpec;
3333
import software.amazon.awssdk.codegen.poet.model.AwsServiceModel;
34+
import software.amazon.awssdk.codegen.poet.model.ResponseMetadataSpec;
3435
import software.amazon.awssdk.codegen.poet.model.ServiceModelCopiers;
3536

3637
class ModelClassGeneratorTasks extends BaseGeneratorTasks {
@@ -59,6 +60,8 @@ protected List<GeneratorTask> createTasks() throws Exception {
5960
.map(safeFunction(spec -> new PoetGeneratorTask(modelClassDir, model.getFileHeader(), spec)))
6061
.forEach(tasks::add);
6162

63+
tasks.add(new PoetGeneratorTask(modelClassDir, model.getFileHeader(), new ResponseMetadataSpec(model)));
64+
6265
return tasks;
6366
}
6467

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ public class CustomizationConfig {
139139

140140
private boolean skipSyncClientGeneration;
141141

142+
/**
143+
* Custom Response metadata
144+
*/
145+
private Map<String, String> customResponseMetadata;
146+
142147
private CustomizationConfig() {
143148
}
144149

@@ -382,4 +387,12 @@ public boolean isSkipSyncClientGeneration() {
382387
public void setSkipSyncClientGeneration(boolean skipSyncClientGeneration) {
383388
this.skipSyncClientGeneration = skipSyncClientGeneration;
384389
}
390+
391+
public Map<String, String> getCustomResponseMetadata() {
392+
return customResponseMetadata;
393+
}
394+
395+
public void setCustomResponseMetadata(Map<String, String> customResponseMetadata) {
396+
this.customResponseMetadata = customResponseMetadata;
397+
}
385398
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
import java.util.Map;
2929
import java.util.stream.Collectors;
3030
import software.amazon.awssdk.awscore.AwsResponse;
31+
import software.amazon.awssdk.awscore.AwsResponseMetadata;
3132
import software.amazon.awssdk.codegen.internal.Utils;
3233
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
3334
import software.amazon.awssdk.codegen.model.service.PaginatorDefinition;
34-
import software.amazon.awssdk.core.SdkResponseMetadata;
3535
import software.amazon.awssdk.utils.IoUtils;
3636

3737
public final class IntermediateModel {
@@ -196,7 +196,7 @@ public String getSdkBaseResponseFqcn() {
196196
}
197197

198198
private String getResponseMetadataClassName() {
199-
return SdkResponseMetadata.class.getName();
199+
return AwsResponseMetadata.class.getName();
200200
}
201201

202202
@JsonIgnore

codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515

1616
package software.amazon.awssdk.codegen.naming;
1717

18-
import static java.util.stream.Collectors.joining;
1918
import static software.amazon.awssdk.codegen.internal.Constant.AUTHORIZER_NAME_PREFIX;
2019
import static software.amazon.awssdk.codegen.internal.Constant.EXCEPTION_CLASS_SUFFIX;
2120
import static software.amazon.awssdk.codegen.internal.Constant.FAULT_CLASS_SUFFIX;
2221
import static software.amazon.awssdk.codegen.internal.Constant.REQUEST_CLASS_SUFFIX;
2322
import static software.amazon.awssdk.codegen.internal.Constant.RESPONSE_CLASS_SUFFIX;
2423
import static software.amazon.awssdk.codegen.internal.Constant.VARIABLE_NAME_SUFFIX;
2524
import static software.amazon.awssdk.codegen.internal.Utils.unCapitalize;
25+
import static software.amazon.awssdk.codegen.utils.NamingUtils.pascalCase;
26+
import static software.amazon.awssdk.codegen.utils.NamingUtils.splitOnWordBoundaries;
2627

2728
import java.util.Arrays;
2829
import java.util.Collections;
@@ -153,13 +154,7 @@ private String concatServiceNameIfShareModel(String serviceName) {
153154
return serviceName;
154155
}
155156

156-
private String pascalCase(String word) {
157-
return Stream.of(splitOnWordBoundaries(word)).map(StringUtils::lowerCase).map(Utils::capitalize).collect(joining());
158-
}
159157

160-
private String pascalCase(String... words) {
161-
return Stream.of(words).map(StringUtils::lowerCase).map(Utils::capitalize).collect(joining());
162-
}
163158

164159
private String getCustomizedPackageName(String serviceName, String defaultPattern) {
165160
return String.format(defaultPattern, StringUtils.lowerCase(serviceName));
@@ -291,30 +286,4 @@ public String getFluentEnumSetterMethodName(String memberName, Shape shape) {
291286

292287
return Utils.unCapitalize(memberName);
293288
}
294-
295-
private String[] splitOnWordBoundaries(String toSplit) {
296-
String result = toSplit;
297-
298-
// All non-alphanumeric characters are spaces
299-
result = result.replaceAll("[^A-Za-z0-9]+", " "); // acm-success -> "acm success"
300-
301-
// If a number has a standalone v in front of it, separate it out (version).
302-
result = result.replaceAll("([^a-z]{2,})v([0-9]+)", "$1 v$2 ") // TESTv4 -> "TEST v4 "
303-
.replaceAll("([^A-Z]{2,})V([0-9]+)", "$1 V$2 "); // TestV4 -> "Test V4 "
304-
305-
// Add a space between camelCased words
306-
result = String.join(" ", result.split("(?<=[a-z])(?=[A-Z]([a-zA-Z]|[0-9]))")); // AcmSuccess -> "Acm Success"
307-
308-
// Add a space after acronyms
309-
result = result.replaceAll("([A-Z]+)([A-Z][a-z])", "$1 $2"); // ACMSuccess -> "ACM Success"
310-
311-
// Add space after a number in the middle of a word
312-
result = result.replaceAll("([0-9])([a-zA-Z])", "$1 $2"); // s3ec2 -> "s3 ec2"
313-
314-
// Remove extra spaces - multiple consecutive ones or those and the beginning/end of words
315-
result = result.replaceAll(" +", " ") // "Foo Bar" -> "Foo Bar"
316-
.trim(); // " Foo " -> Foo
317-
318-
return result.split(" ");
319-
}
320289
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtensions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,12 @@ public ClassName getResponseClassForPaginatedSyncOperation(String operationName)
8282
public ClassName getResponseClassForPaginatedAsyncOperation(String operationName) {
8383
return ClassName.get(model.getMetadata().getFullPaginatorsPackageName(), operationName + "Publisher");
8484
}
85+
86+
/**
87+
* @return ResponseMetadata className. eg: "S3ResponseMetadata"
88+
*/
89+
public ClassName getResponseMetadataClass() {
90+
return ClassName.get(model.getMetadata().getFullModelPackageName(),
91+
model.getSdkResponseBaseClassName() + "Metadata");
92+
}
8593
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryXmlProtocolSpec.java

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import software.amazon.awssdk.awscore.exception.AwsServiceException;
3131
import software.amazon.awssdk.awscore.http.response.DefaultErrorResponseHandler;
3232
import software.amazon.awssdk.awscore.http.response.StaxResponseHandler;
33+
import software.amazon.awssdk.awscore.internal.protocol.xml.StaxOperationMetadata;
3334
import software.amazon.awssdk.awscore.protocol.xml.StandardErrorUnmarshaller;
3435
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
3536
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
@@ -92,22 +93,15 @@ public CodeBlock responseHandler(IntermediateModel model,
9293
ClassName unmarshaller = poetExtensions.getTransformClass(opModel.getReturnType().getReturnType() + "Unmarshaller");
9394
ClassName responseType = poetExtensions.getModelClass(opModel.getReturnType().getReturnType());
9495

95-
if (opModel.hasStreamingOutput()) {
96-
return CodeBlock.builder()
97-
.addStatement("\n\n$T<$T> responseHandler = $T.createStreamingResponseHandler(new $T())",
98-
HttpResponseHandler.class,
99-
responseType,
100-
StaxResponseHandler.class,
101-
unmarshaller)
102-
.build();
103-
}
10496
return CodeBlock.builder()
105-
.addStatement("\n\n$T<$T> responseHandler = new $T<$T>(new $T())",
106-
StaxResponseHandler.class,
97+
.addStatement("\n\n$T<$T> responseHandler = new $T<>(new $T(), new $T().withHasStreamingSuccessResponse"
98+
+ "($L))",
99+
HttpResponseHandler.class,
107100
responseType,
108101
StaxResponseHandler.class,
109-
responseType,
110-
unmarshaller)
102+
unmarshaller,
103+
StaxOperationMetadata.class,
104+
opModel.hasStreamingOutput())
111105
.build();
112106
}
113107

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

Lines changed: 109 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
package software.amazon.awssdk.codegen.poet.model;
1717

1818
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.CodeBlock;
20+
import com.squareup.javapoet.FieldSpec;
1921
import com.squareup.javapoet.MethodSpec;
2022
import com.squareup.javapoet.TypeSpec;
2123
import javax.lang.model.element.Modifier;
2224
import software.amazon.awssdk.awscore.AwsResponse;
25+
import software.amazon.awssdk.awscore.AwsResponseMetadata;
2326
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2427
import software.amazon.awssdk.codegen.poet.ClassSpec;
2528
import software.amazon.awssdk.codegen.poet.PoetExtensions;
@@ -28,26 +31,33 @@
2831
public class AwsServiceBaseResponseSpec implements ClassSpec {
2932
private final IntermediateModel intermediateModel;
3033
private final PoetExtensions poetExtensions;
34+
private final ClassName responseMetadata;
3135

3236
public AwsServiceBaseResponseSpec(IntermediateModel intermediateModel) {
3337
this.intermediateModel = intermediateModel;
3438
this.poetExtensions = new PoetExtensions(this.intermediateModel);
39+
this.responseMetadata = poetExtensions.getResponseMetadataClass();
3540
}
3641

3742
@Override
3843
public TypeSpec poetSpec() {
39-
TypeSpec.Builder builder = TypeSpec.classBuilder(className())
40-
.addAnnotation(PoetUtils.generatedAnnotation())
41-
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
42-
.superclass(ClassName.get(AwsResponse.class))
43-
.addMethod(MethodSpec.constructorBuilder()
44-
.addModifiers(Modifier.PROTECTED)
45-
.addParameter(className().nestedClass("Builder"), "builder")
46-
.addStatement("super(builder)")
47-
.build())
48-
.addType(builderInterfaceSpec())
49-
.addType(builderImplSpec());
50-
return builder.build();
44+
MethodSpec.Builder constructorBuilder =
45+
MethodSpec.constructorBuilder()
46+
.addModifiers(Modifier.PROTECTED)
47+
.addParameter(className().nestedClass("Builder"), "builder")
48+
.addStatement("super(builder)");
49+
50+
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className())
51+
.addAnnotation(PoetUtils.generatedAnnotation())
52+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
53+
.superclass(ClassName.get(AwsResponse.class))
54+
.addType(builderInterfaceSpec())
55+
.addType(builderImplSpec());
56+
57+
addResponseMetadata(classBuilder, constructorBuilder);
58+
59+
classBuilder.addMethod(constructorBuilder.build());
60+
return classBuilder.build();
5161
}
5262

5363
@Override
@@ -56,34 +66,95 @@ public ClassName className() {
5666
}
5767

5868
private TypeSpec builderInterfaceSpec() {
59-
return TypeSpec.interfaceBuilder("Builder")
60-
.addModifiers(Modifier.PUBLIC)
61-
.addSuperinterface(ClassName.get(AwsResponse.class).nestedClass("Builder"))
62-
63-
.addMethod(MethodSpec.methodBuilder("build")
64-
.addAnnotation(Override.class)
65-
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
66-
.returns(className())
67-
.build())
68-
.build();
69+
TypeSpec.Builder builder = TypeSpec.interfaceBuilder("Builder")
70+
.addModifiers(Modifier.PUBLIC)
71+
.addSuperinterface(ClassName.get(AwsResponse.class).nestedClass("Builder"))
72+
.addMethod(MethodSpec.methodBuilder("build")
73+
.addAnnotation(Override.class)
74+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
75+
.returns(className())
76+
.build());
77+
78+
addResponseMetadataToInterface(builder);
79+
return builder.build();
80+
}
81+
82+
private ClassName builderInterfaceName() {
83+
return className().nestedClass("Builder");
6984
}
7085

7186
private TypeSpec builderImplSpec() {
72-
return TypeSpec.classBuilder("BuilderImpl")
73-
.addModifiers(Modifier.PROTECTED, Modifier.STATIC, Modifier.ABSTRACT)
74-
.addSuperinterface(className().nestedClass("Builder"))
75-
.superclass(ClassName.get(AwsResponse.class).nestedClass("BuilderImpl"))
76-
77-
.addMethod(MethodSpec.constructorBuilder()
78-
.addModifiers(Modifier.PROTECTED)
79-
.build())
80-
81-
.addMethod(MethodSpec.constructorBuilder()
82-
.addModifiers(Modifier.PROTECTED)
83-
.addParameter(className(), "response")
84-
.addStatement("super(response)")
85-
.build())
86-
87-
.build();
87+
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
88+
.addModifiers(Modifier.PROTECTED)
89+
.addParameter(className(), "response")
90+
.addStatement("super(response)")
91+
.addStatement("this.responseMetadata = response.responseMetadata()");
92+
93+
TypeSpec.Builder classBuilder = TypeSpec.classBuilder("BuilderImpl")
94+
.addModifiers(Modifier.PROTECTED, Modifier.STATIC, Modifier.ABSTRACT)
95+
.addSuperinterface(className().nestedClass("Builder"))
96+
.superclass(ClassName.get(AwsResponse.class).nestedClass("BuilderImpl"))
97+
.addMethod(MethodSpec.constructorBuilder()
98+
.addModifiers(Modifier.PROTECTED)
99+
.build())
100+
.addMethod(constructorBuilder.build());
101+
102+
addResponseMetadataToImpl(classBuilder);
103+
104+
return classBuilder.build();
105+
}
106+
107+
private void addResponseMetadata(TypeSpec.Builder classBuilder, MethodSpec.Builder constructorBuilder) {
108+
constructorBuilder.addStatement("this.responseMetadata = builder.responseMetadata()");
109+
110+
classBuilder.addField(FieldSpec.builder(responseMetadata, "responseMetadata",
111+
Modifier.PRIVATE, Modifier.FINAL)
112+
.build());
113+
114+
classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
115+
.returns(responseMetadata)
116+
.addModifiers(Modifier.PUBLIC)
117+
.addAnnotation(Override.class)
118+
.addCode("return responseMetadata;")
119+
.build());
120+
121+
}
122+
123+
private void addResponseMetadataToInterface(TypeSpec.Builder builder) {
124+
builder.addMethod(MethodSpec.methodBuilder("responseMetadata")
125+
.returns(responseMetadata)
126+
.addAnnotation(Override.class)
127+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
128+
.build());
129+
130+
builder.addMethod(MethodSpec.methodBuilder("responseMetadata")
131+
.addParameter(AwsResponseMetadata.class, "metadata")
132+
.returns(builderInterfaceName())
133+
.addAnnotation(Override.class)
134+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
135+
.build());
136+
}
137+
138+
private void addResponseMetadataToImpl(TypeSpec.Builder classBuilder) {
139+
classBuilder.addField(FieldSpec.builder(responseMetadata, "responseMetadata", Modifier.PRIVATE).build());
140+
141+
classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
142+
.returns(responseMetadata)
143+
.addAnnotation(Override.class)
144+
.addModifiers(Modifier.PUBLIC)
145+
.addStatement("return responseMetadata")
146+
.build());
147+
148+
classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
149+
.addParameter(AwsResponseMetadata.class, "responseMetadata")
150+
.returns(builderInterfaceName())
151+
.addAnnotation(Override.class)
152+
.addModifiers(Modifier.PUBLIC)
153+
.addCode(CodeBlock.builder()
154+
.add("this.responseMetadata = $T.create(responseMetadata);\n",
155+
responseMetadata)
156+
.add("return this;")
157+
.build())
158+
.build());
88159
}
89160
}

0 commit comments

Comments
 (0)