Skip to content

Add support for AwsResponseMetadata #701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-b2d6616.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"category": "AWS SDK for Java v2",
"type": "feature",
"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)"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import software.amazon.awssdk.codegen.poet.model.AwsServiceBaseRequestSpec;
import software.amazon.awssdk.codegen.poet.model.AwsServiceBaseResponseSpec;
import software.amazon.awssdk.codegen.poet.model.AwsServiceModel;
import software.amazon.awssdk.codegen.poet.model.ResponseMetadataSpec;
import software.amazon.awssdk.codegen.poet.model.ServiceModelCopiers;

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

tasks.add(new PoetGeneratorTask(modelClassDir, model.getFileHeader(), new ResponseMetadataSpec(model)));

return tasks;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ public class CustomizationConfig {

private boolean skipSyncClientGeneration;

/**
* Custom Response metadata
*/
private Map<String, String> customResponseMetadata;

private CustomizationConfig() {
}

Expand Down Expand Up @@ -382,4 +387,12 @@ public boolean isSkipSyncClientGeneration() {
public void setSkipSyncClientGeneration(boolean skipSyncClientGeneration) {
this.skipSyncClientGeneration = skipSyncClientGeneration;
}

public Map<String, String> getCustomResponseMetadata() {
return customResponseMetadata;
}

public void setCustomResponseMetadata(Map<String, String> customResponseMetadata) {
this.customResponseMetadata = customResponseMetadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
import java.util.Map;
import java.util.stream.Collectors;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.awscore.AwsResponseMetadata;
import software.amazon.awssdk.codegen.internal.Utils;
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
import software.amazon.awssdk.codegen.model.service.PaginatorDefinition;
import software.amazon.awssdk.core.SdkResponseMetadata;
import software.amazon.awssdk.utils.IoUtils;

public final class IntermediateModel {
Expand Down Expand Up @@ -196,7 +196,7 @@ public String getSdkBaseResponseFqcn() {
}

private String getResponseMetadataClassName() {
return SdkResponseMetadata.class.getName();
return AwsResponseMetadata.class.getName();
}

@JsonIgnore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@

package software.amazon.awssdk.codegen.naming;

import static java.util.stream.Collectors.joining;
import static software.amazon.awssdk.codegen.internal.Constant.AUTHORIZER_NAME_PREFIX;
import static software.amazon.awssdk.codegen.internal.Constant.EXCEPTION_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.FAULT_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.REQUEST_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.RESPONSE_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.VARIABLE_NAME_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Utils.unCapitalize;
import static software.amazon.awssdk.codegen.utils.NamingUtils.pascalCase;
import static software.amazon.awssdk.codegen.utils.NamingUtils.splitOnWordBoundaries;

import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -153,13 +154,7 @@ private String concatServiceNameIfShareModel(String serviceName) {
return serviceName;
}

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

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

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

return Utils.unCapitalize(memberName);
}

private String[] splitOnWordBoundaries(String toSplit) {
String result = toSplit;

// All non-alphanumeric characters are spaces
result = result.replaceAll("[^A-Za-z0-9]+", " "); // acm-success -> "acm success"

// If a number has a standalone v in front of it, separate it out (version).
result = result.replaceAll("([^a-z]{2,})v([0-9]+)", "$1 v$2 ") // TESTv4 -> "TEST v4 "
.replaceAll("([^A-Z]{2,})V([0-9]+)", "$1 V$2 "); // TestV4 -> "Test V4 "

// Add a space between camelCased words
result = String.join(" ", result.split("(?<=[a-z])(?=[A-Z]([a-zA-Z]|[0-9]))")); // AcmSuccess -> "Acm Success"

// Add a space after acronyms
result = result.replaceAll("([A-Z]+)([A-Z][a-z])", "$1 $2"); // ACMSuccess -> "ACM Success"

// Add space after a number in the middle of a word
result = result.replaceAll("([0-9])([a-zA-Z])", "$1 $2"); // s3ec2 -> "s3 ec2"

// Remove extra spaces - multiple consecutive ones or those and the beginning/end of words
result = result.replaceAll(" +", " ") // "Foo Bar" -> "Foo Bar"
.trim(); // " Foo " -> Foo

return result.split(" ");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,12 @@ public ClassName getResponseClassForPaginatedSyncOperation(String operationName)
public ClassName getResponseClassForPaginatedAsyncOperation(String operationName) {
return ClassName.get(model.getMetadata().getFullPaginatorsPackageName(), operationName + "Publisher");
}

/**
* @return ResponseMetadata className. eg: "S3ResponseMetadata"
*/
public ClassName getResponseMetadataClass() {
return ClassName.get(model.getMetadata().getFullModelPackageName(),
model.getSdkResponseBaseClassName() + "Metadata");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.awscore.http.response.DefaultErrorResponseHandler;
import software.amazon.awssdk.awscore.http.response.StaxResponseHandler;
import software.amazon.awssdk.awscore.internal.protocol.xml.StaxOperationMetadata;
import software.amazon.awssdk.awscore.protocol.xml.StandardErrorUnmarshaller;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
Expand Down Expand Up @@ -92,22 +93,15 @@ public CodeBlock responseHandler(IntermediateModel model,
ClassName unmarshaller = poetExtensions.getTransformClass(opModel.getReturnType().getReturnType() + "Unmarshaller");
ClassName responseType = poetExtensions.getModelClass(opModel.getReturnType().getReturnType());

if (opModel.hasStreamingOutput()) {
return CodeBlock.builder()
.addStatement("\n\n$T<$T> responseHandler = $T.createStreamingResponseHandler(new $T())",
HttpResponseHandler.class,
responseType,
StaxResponseHandler.class,
unmarshaller)
.build();
}
return CodeBlock.builder()
.addStatement("\n\n$T<$T> responseHandler = new $T<$T>(new $T())",
StaxResponseHandler.class,
.addStatement("\n\n$T<$T> responseHandler = new $T<>(new $T(), new $T().withHasStreamingSuccessResponse"
+ "($L))",
HttpResponseHandler.class,
responseType,
StaxResponseHandler.class,
responseType,
unmarshaller)
unmarshaller,
StaxOperationMetadata.class,
opModel.hasStreamingOutput())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
package software.amazon.awssdk.codegen.poet.model;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.awscore.AwsResponseMetadata;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetExtensions;
Expand All @@ -28,26 +31,33 @@
public class AwsServiceBaseResponseSpec implements ClassSpec {
private final IntermediateModel intermediateModel;
private final PoetExtensions poetExtensions;
private final ClassName responseMetadata;

public AwsServiceBaseResponseSpec(IntermediateModel intermediateModel) {
this.intermediateModel = intermediateModel;
this.poetExtensions = new PoetExtensions(this.intermediateModel);
this.responseMetadata = poetExtensions.getResponseMetadataClass();
}

@Override
public TypeSpec poetSpec() {
TypeSpec.Builder builder = TypeSpec.classBuilder(className())
.addAnnotation(PoetUtils.generatedAnnotation())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.superclass(ClassName.get(AwsResponse.class))
.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.addParameter(className().nestedClass("Builder"), "builder")
.addStatement("super(builder)")
.build())
.addType(builderInterfaceSpec())
.addType(builderImplSpec());
return builder.build();
MethodSpec.Builder constructorBuilder =
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.addParameter(className().nestedClass("Builder"), "builder")
.addStatement("super(builder)");

TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className())
.addAnnotation(PoetUtils.generatedAnnotation())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.superclass(ClassName.get(AwsResponse.class))
.addType(builderInterfaceSpec())
.addType(builderImplSpec());

addResponseMetadata(classBuilder, constructorBuilder);

classBuilder.addMethod(constructorBuilder.build());
return classBuilder.build();
}

@Override
Expand All @@ -56,34 +66,95 @@ public ClassName className() {
}

private TypeSpec builderInterfaceSpec() {
return TypeSpec.interfaceBuilder("Builder")
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ClassName.get(AwsResponse.class).nestedClass("Builder"))

.addMethod(MethodSpec.methodBuilder("build")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.returns(className())
.build())
.build();
TypeSpec.Builder builder = TypeSpec.interfaceBuilder("Builder")
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ClassName.get(AwsResponse.class).nestedClass("Builder"))
.addMethod(MethodSpec.methodBuilder("build")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.returns(className())
.build());

addResponseMetadataToInterface(builder);
return builder.build();
}

private ClassName builderInterfaceName() {
return className().nestedClass("Builder");
}

private TypeSpec builderImplSpec() {
return TypeSpec.classBuilder("BuilderImpl")
.addModifiers(Modifier.PROTECTED, Modifier.STATIC, Modifier.ABSTRACT)
.addSuperinterface(className().nestedClass("Builder"))
.superclass(ClassName.get(AwsResponse.class).nestedClass("BuilderImpl"))

.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.build())

.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.addParameter(className(), "response")
.addStatement("super(response)")
.build())

.build();
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.addParameter(className(), "response")
.addStatement("super(response)")
.addStatement("this.responseMetadata = response.responseMetadata()");

TypeSpec.Builder classBuilder = TypeSpec.classBuilder("BuilderImpl")
.addModifiers(Modifier.PROTECTED, Modifier.STATIC, Modifier.ABSTRACT)
.addSuperinterface(className().nestedClass("Builder"))
.superclass(ClassName.get(AwsResponse.class).nestedClass("BuilderImpl"))
.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PROTECTED)
.build())
.addMethod(constructorBuilder.build());

addResponseMetadataToImpl(classBuilder);

return classBuilder.build();
}

private void addResponseMetadata(TypeSpec.Builder classBuilder, MethodSpec.Builder constructorBuilder) {
constructorBuilder.addStatement("this.responseMetadata = builder.responseMetadata()");

classBuilder.addField(FieldSpec.builder(responseMetadata, "responseMetadata",
Modifier.PRIVATE, Modifier.FINAL)
.build());

classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
.returns(responseMetadata)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addCode("return responseMetadata;")
.build());

}

private void addResponseMetadataToInterface(TypeSpec.Builder builder) {
builder.addMethod(MethodSpec.methodBuilder("responseMetadata")
.returns(responseMetadata)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.build());

builder.addMethod(MethodSpec.methodBuilder("responseMetadata")
.addParameter(AwsResponseMetadata.class, "metadata")
.returns(builderInterfaceName())
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.build());
}

private void addResponseMetadataToImpl(TypeSpec.Builder classBuilder) {
classBuilder.addField(FieldSpec.builder(responseMetadata, "responseMetadata", Modifier.PRIVATE).build());

classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
.returns(responseMetadata)
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addStatement("return responseMetadata")
.build());

classBuilder.addMethod(MethodSpec.methodBuilder("responseMetadata")
.addParameter(AwsResponseMetadata.class, "responseMetadata")
.returns(builderInterfaceName())
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addCode(CodeBlock.builder()
.add("this.responseMetadata = $T.create(responseMetadata);\n",
responseMetadata)
.add("return this;")
.build())
.build());
}
}
Loading