diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddOperations.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddOperations.java index d264a2035f7e..1b9f73858e00 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddOperations.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddOperations.java @@ -73,7 +73,7 @@ private static boolean isBlobShape(Shape shape) { * @return True if shape is a String type. False otherwise */ private static boolean isStringShape(Shape shape) { - return shape != null && "String".equals(shape.getType()); + return shape != null && "String".equalsIgnoreCase(shape.getType()); } /** diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java index 2a70f79359f1..d8a61167a7d8 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java @@ -38,7 +38,8 @@ public static CodegenCustomizationProcessor getProcessorFor( new UseLegacyEventGenerationSchemeProcessor(), new NewAndLegacyEventStreamProcessor(), new S3RemoveBucketFromUriProcessor(), - new S3ControlRemoveAccountIdHostPrefixProcessor() + new S3ControlRemoveAccountIdHostPrefixProcessor(), + new ExplicitStringPayloadQueryProtocolProcessor() ); } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/ExplicitStringPayloadQueryProtocolProcessor.java b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/ExplicitStringPayloadQueryProtocolProcessor.java new file mode 100644 index 000000000000..273c231b136d --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/ExplicitStringPayloadQueryProtocolProcessor.java @@ -0,0 +1,73 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.customization.processors; + +import java.util.Map; +import software.amazon.awssdk.codegen.customization.CodegenCustomizationProcessor; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.service.Input; +import software.amazon.awssdk.codegen.model.service.Member; +import software.amazon.awssdk.codegen.model.service.Output; +import software.amazon.awssdk.codegen.model.service.ServiceModel; +import software.amazon.awssdk.codegen.model.service.Shape; + +/** + * Operations with explicit String payloads are not supported for services with Query protocol. We fail the codegen if the + * httpPayload or eventPayload trait is set on a String. + */ +public class ExplicitStringPayloadQueryProtocolProcessor implements CodegenCustomizationProcessor { + @Override + public void preprocess(ServiceModel serviceModel) { + String protocol = serviceModel.getMetadata().getProtocol(); + if (!"ec2".equals(protocol) && !"query".equals(protocol)) { + return; + } + + Map c2jShapes = serviceModel.getShapes(); + + serviceModel.getOperations().forEach((operationName, op) -> { + + Input input = op.getInput(); + if (input != null && isExplicitStringPayload(c2jShapes, c2jShapes.get(input.getShape()))) { + throw new RuntimeException("Operations with explicit String payloads are not supported for Query " + + "protocols. Unsupported operation: " + operationName); + + } + + Output output = op.getOutput(); + if (output != null && isExplicitStringPayload(c2jShapes, c2jShapes.get(output.getShape()))) { + throw new RuntimeException("Operations with explicit String payloads are not supported for Query " + + "protocols. Unsupported operation: " + operationName); + + } + }); + } + + @Override + public void postprocess(IntermediateModel intermediateModel) { + // no-op + } + + private boolean isExplicitStringPayload(Map c2jShapes, Shape shape) { + if (shape.getPayload() == null) { + return false; + } + + Member payloadMember = shape.getMembers().get(shape.getPayload()); + Shape payloadShape = c2jShapes.get(payloadMember.getShape()); + return payloadShape != null && "String".equalsIgnoreCase(payloadShape.getType()); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json index a3c379d189d6..940d58871464 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/query/service-2.json @@ -325,7 +325,7 @@ "ChecksumStructure":{ "type":"structure", "members":{ - "stringMember":{"shape":"subMember"}, + "Body":{"shape":"Body"}, "ChecksumMode":{ "shape":"ChecksumMode", "location":"header", @@ -337,7 +337,7 @@ "locationName":"x-amz-checksum-algorithm" } }, - "payload":"stringMember" + "payload":"Body" }, "String":{"type":"string"}, "BearerAuthOperationRequest": { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-class.java index 81eb8e1aba4e..f3c88ecbb220 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-class.java @@ -612,7 +612,7 @@ public CompletableFuture getOperationWithCheck apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Json Service"); apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "GetOperationWithChecksum"); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(false).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( operationMetadata, GetOperationWithChecksumResponse::builder); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java index a2a8905fe12a..06f7808b8d9d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java @@ -277,7 +277,7 @@ public GetOperationWithChecksumResponse getOperationWithChecksum( GetOperationWithChecksumRequest getOperationWithChecksumRequest) throws AwsServiceException, SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(false).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( operationMetadata, GetOperationWithChecksumResponse::builder);