From 91166055a460aa81ba22ba8d73d5affaf22384e9 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:20:22 -0700 Subject: [PATCH 01/11] Include shape name in REQUEST_URI_NOT_FOUND validation error message --- .../amazon/awssdk/codegen/AddShapes.java | 8 ++- .../awssdk/codegen/CodeGeneratorTest.java | 23 ++++++++ .../uri-on-non-input-shape-service.json | 57 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 19600e33210e..55975faf69cd 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -367,7 +367,13 @@ private String findRequestUri(Shape parentShape, Map allC2jShapes return operation.map(o -> o.getHttp().getRequestUri()) .orElseThrow(() -> { - String detailMsg = "Could not find request URI for input shape for operation: " + operation; + String shapeName = allC2jShapes.entrySet().stream() + .filter(e -> e.getValue().equals(parentShape)) + .map(Map.Entry::getKey) + .findFirst() + .orElse("unknown"); + String detailMsg = "Could not find request URI for input shape '" + shapeName + + "'. No operation was found that references this shape as its input."; ValidationEntry entry = new ValidationEntry().withErrorId(ValidationErrorId.REQUEST_URI_NOT_FOUND) .withDetailMessage(detailMsg) diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java index 05a492ca24c4..0ce91b61b576 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java @@ -48,6 +48,7 @@ import software.amazon.awssdk.codegen.poet.ClientTestModels; import software.amazon.awssdk.codegen.validation.ModelInvalidException; import software.amazon.awssdk.codegen.validation.ModelValidator; +import software.amazon.awssdk.codegen.validation.ValidationEntry; import software.amazon.awssdk.codegen.validation.ValidationErrorId; public class CodeGeneratorTest { @@ -176,6 +177,23 @@ void execute_endpointsTestReferencesUnknownOperationMember_throwsValidationError }); } + @Test + void execute_uriLocationOnNonInputShape_throwsValidationErrorWithShapeName() throws IOException { + C2jModels models = C2jModels.builder() + .customizationConfig(CustomizationConfig.create()) + .serviceModel(getUriOnNonInputShapeServiceModel()) + .build(); + + assertThatThrownBy(() -> generateCodeFromC2jModels(models, outputDir, true, Collections.emptyList())) + .isInstanceOf(ModelInvalidException.class) + .matches(e -> { + ModelInvalidException ex = (ModelInvalidException) e; + ValidationEntry entry = ex.validationEntries().get(0); + return entry.getErrorId() == ValidationErrorId.REQUEST_URI_NOT_FOUND + && entry.getDetailMessage().contains("No operation was found"); + }); + } + @Test void execute_operationHasNoRequestUri_throwsValidationError() throws IOException { C2jModels models = C2jModels.builder() @@ -244,6 +262,11 @@ private ServiceModel getMissingRequestUriServiceModel() throws IOException { return Jackson.load(ServiceModel.class, json); } + private ServiceModel getUriOnNonInputShapeServiceModel() throws IOException { + String json = resourceAsString("uri-on-non-input-shape-service.json"); + return Jackson.load(ServiceModel.class, json); + } + private String resourceAsString(String name) throws IOException { ByteArrayOutputStream baos; try (InputStream resourceAsStream = getClass().getResourceAsStream(name)) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json new file mode 100644 index 000000000000..7462f20501db --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json @@ -0,0 +1,57 @@ +{ + "version": "2.0", + "metadata": { + "apiVersion": "2010-05-08", + "endpointPrefix": "json-service-endpoint", + "globalEndpoint": "json-service.amazonaws.com", + "protocol": "rest-json", + "serviceAbbreviation": "Rest Json Service", + "serviceFullName": "Some Service That Uses Rest-Json Protocol", + "serviceId": "Rest Json Service", + "signingName": "json-service", + "signatureVersion": "v4", + "uid": "json-service-2010-05-08", + "xmlNamespace": "https://json-service.amazonaws.com/doc/2010-05-08/" + }, + "operations": { + "SomeOperation": { + "name": "SomeOperation", + "http": { + "method": "POST", + "requestUri": "/things/{thingId}" + }, + "input": { + "shape": "SomeOperationRequest" + } + } + }, + "shapes": { + "SomeOperationRequest": { + "type": "structure", + "members": { + "thingId": { + "shape": "String", + "location": "uri", + "locationName": "thingId" + }, + "options": { + "shape": "NestedOptions" + } + } + }, + "NestedOptions": { + "type": "structure", + "members": { + "pageSize": { + "shape": "String", + "location": "uri", + "locationName": "pageSize" + } + } + }, + "String": { + "type": "string" + } + }, + "documentation": "A service with a uri-bound member on a non-input shape" +} From 1b094c08c3fa737beff845e967a57d079edf4568 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:50:26 -0700 Subject: [PATCH 02/11] Fix codegen logic to allow non input shape uri bound member --- .../amazon/awssdk/codegen/AddShapes.java | 46 ++++++------------- .../awssdk/codegen/CodeGeneratorTest.java | 14 ++---- 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 55975faf69cd..725bf8f38e62 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -21,7 +21,6 @@ import static software.amazon.awssdk.codegen.internal.Utils.isMapShape; import static software.amazon.awssdk.codegen.internal.Utils.isScalar; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -38,15 +37,10 @@ import software.amazon.awssdk.codegen.model.intermediate.VariableModel; import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.codegen.model.service.Member; -import software.amazon.awssdk.codegen.model.service.Operation; import software.amazon.awssdk.codegen.model.service.ServiceModel; import software.amazon.awssdk.codegen.model.service.Shape; import software.amazon.awssdk.codegen.naming.NamingStrategy; import software.amazon.awssdk.codegen.utils.ProtocolUtils; -import software.amazon.awssdk.codegen.validation.ModelInvalidException; -import software.amazon.awssdk.codegen.validation.ValidationEntry; -import software.amazon.awssdk.codegen.validation.ValidationErrorId; -import software.amazon.awssdk.codegen.validation.ValidationErrorSeverity; import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; @@ -342,9 +336,9 @@ private boolean isRequiredMember(String memberName, Shape memberShape) { */ private boolean isGreedy(Shape parentShape, Map allC2jShapes, ParameterHttpMapping mapping) { if (mapping.getLocation() == Location.URI) { - // If the location is URI we can assume the parent shape is an input shape. - String requestUri = findRequestUri(parentShape, allC2jShapes); - if (requestUri.contains(String.format("{%s+}", mapping.getMarshallLocationName()))) { + Optional requestUri = findRequestUri(parentShape, allC2jShapes); + if (requestUri.isPresent() + && requestUri.get().contains(String.format("{%s+}", mapping.getMarshallLocationName()))) { return true; } } @@ -353,33 +347,19 @@ private boolean isGreedy(Shape parentShape, Map allC2jShapes, Par /** * Given an input shape, finds the Request URI for the operation that input is referenced from. + * Per the Smithy spec, httpLabel on non-input shapes has no meaning and is ignored, + * so this returns Optional.empty() if the shape is not a direct operation input. * - * @param parentShape Input shape to find operation's request URI for. + * @param parentShape Shape to find operation's request URI for. * @param allC2jShapes All shapes in the service model. - * @return Request URI for operation. - * @throws RuntimeException If operation can't be found. + * @return Request URI for operation, or empty if the shape is not a direct operation input. */ - private String findRequestUri(Shape parentShape, Map allC2jShapes) { - Optional operation = builder.getService().getOperations().values().stream() - .filter(o -> o.getInput() != null) - .filter(o -> allC2jShapes.get(o.getInput().getShape()).equals(parentShape)) - .findFirst(); - - return operation.map(o -> o.getHttp().getRequestUri()) - .orElseThrow(() -> { - String shapeName = allC2jShapes.entrySet().stream() - .filter(e -> e.getValue().equals(parentShape)) - .map(Map.Entry::getKey) - .findFirst() - .orElse("unknown"); - String detailMsg = "Could not find request URI for input shape '" + shapeName - + "'. No operation was found that references this shape as its input."; - ValidationEntry entry = - new ValidationEntry().withErrorId(ValidationErrorId.REQUEST_URI_NOT_FOUND) - .withDetailMessage(detailMsg) - .withSeverity(ValidationErrorSeverity.DANGER); - return ModelInvalidException.builder().validationEntries(Collections.singletonList(entry)).build(); - }); + private Optional findRequestUri(Shape parentShape, Map allC2jShapes) { + return builder.getService().getOperations().values().stream() + .filter(o -> o.getInput() != null) + .filter(o -> allC2jShapes.get(o.getInput().getShape()).equals(parentShape)) + .findFirst() + .map(o -> o.getHttp().getRequestUri()); } private String deriveUnmarshallerLocationName(Shape memberShape, String memberName, Member member) { diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java index 0ce91b61b576..1f94a8b3849a 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.codegen; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -178,20 +179,15 @@ void execute_endpointsTestReferencesUnknownOperationMember_throwsValidationError } @Test - void execute_uriLocationOnNonInputShape_throwsValidationErrorWithShapeName() throws IOException { + void execute_uriLocationOnNonInputShape_isIgnored() throws IOException { C2jModels models = C2jModels.builder() .customizationConfig(CustomizationConfig.create()) .serviceModel(getUriOnNonInputShapeServiceModel()) .build(); - assertThatThrownBy(() -> generateCodeFromC2jModels(models, outputDir, true, Collections.emptyList())) - .isInstanceOf(ModelInvalidException.class) - .matches(e -> { - ModelInvalidException ex = (ModelInvalidException) e; - ValidationEntry entry = ex.validationEntries().get(0); - return entry.getErrorId() == ValidationErrorId.REQUEST_URI_NOT_FOUND - && entry.getDetailMessage().contains("No operation was found"); - }); + // Per the Smithy spec, httpLabel on non-input shapes has no meaning and is simply ignored. + assertThatNoException().isThrownBy( + () -> generateCodeFromC2jModels(models, outputDir, true, Collections.emptyList())); } @Test From 48e1b37134583cc10c1c1e77c283042d757bba2f Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:29:50 -0700 Subject: [PATCH 03/11] Fix logic to ignore instead of throw --- .../amazon/awssdk/codegen/AddShapes.java | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 725bf8f38e62..5344016041e8 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -21,6 +21,7 @@ import static software.amazon.awssdk.codegen.internal.Utils.isMapShape; import static software.amazon.awssdk.codegen.internal.Utils.isScalar; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -37,10 +38,15 @@ import software.amazon.awssdk.codegen.model.intermediate.VariableModel; import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.codegen.model.service.Member; +import software.amazon.awssdk.codegen.model.service.Operation; import software.amazon.awssdk.codegen.model.service.ServiceModel; import software.amazon.awssdk.codegen.model.service.Shape; import software.amazon.awssdk.codegen.naming.NamingStrategy; import software.amazon.awssdk.codegen.utils.ProtocolUtils; +import software.amazon.awssdk.codegen.validation.ModelInvalidException; +import software.amazon.awssdk.codegen.validation.ValidationEntry; +import software.amazon.awssdk.codegen.validation.ValidationErrorId; +import software.amazon.awssdk.codegen.validation.ValidationErrorSeverity; import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; @@ -349,17 +355,38 @@ private boolean isGreedy(Shape parentShape, Map allC2jShapes, Par * Given an input shape, finds the Request URI for the operation that input is referenced from. * Per the Smithy spec, httpLabel on non-input shapes has no meaning and is ignored, * so this returns Optional.empty() if the shape is not a direct operation input. - * - * @param parentShape Shape to find operation's request URI for. - * @param allC2jShapes All shapes in the service model. - * @return Request URI for operation, or empty if the shape is not a direct operation input. + * If the shape IS a direct operation input but the operation is missing a requestUri, + * a validation error is thrown. */ private Optional findRequestUri(Shape parentShape, Map allC2jShapes) { - return builder.getService().getOperations().values().stream() - .filter(o -> o.getInput() != null) - .filter(o -> allC2jShapes.get(o.getInput().getShape()).equals(parentShape)) - .findFirst() - .map(o -> o.getHttp().getRequestUri()); + Optional operation = builder.getService().getOperations().values().stream() + .filter(o -> o.getInput() != null) + .filter(o -> allC2jShapes.get(o.getInput().getShape()).equals(parentShape)) + .findFirst(); + + if (!operation.isPresent()) { + // Not a direct operation input shape, should be ignored. + // https://smithy.io/2.0/spec/http-bindings.html#httplabel-is-only-used-on-top-level-input + return Optional.empty(); + } + + String requestUri = operation.get().getHttp().getRequestUri(); + if (requestUri == null) { + String shapeName = allC2jShapes.entrySet().stream() + .filter(e -> e.getValue().equals(parentShape)) + .map(Map.Entry::getKey) + .findFirst() + .get(); + String detailMsg = "Could not find request URI for input shape '" + shapeName + + "'. No operation was found that references this shape as its input."; + ValidationEntry entry = + new ValidationEntry().withErrorId(ValidationErrorId.REQUEST_URI_NOT_FOUND) + .withDetailMessage(detailMsg) + .withSeverity(ValidationErrorSeverity.DANGER); + throw ModelInvalidException.builder().validationEntries(Collections.singletonList(entry)).build(); + } + + return Optional.of(requestUri); } private String deriveUnmarshallerLocationName(Shape memberShape, String memberName, Member member) { From cbb38f4d2d7ab9a2f67b184a22c14006d5fa4e31 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:48:30 -0700 Subject: [PATCH 04/11] Fix javadoc --- .../software/amazon/awssdk/codegen/AddShapes.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 5344016041e8..14766b3d46be 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -352,11 +352,14 @@ private boolean isGreedy(Shape parentShape, Map allC2jShapes, Par } /** - * Given an input shape, finds the Request URI for the operation that input is referenced from. - * Per the Smithy spec, httpLabel on non-input shapes has no meaning and is ignored, - * so this returns Optional.empty() if the shape is not a direct operation input. - * If the shape IS a direct operation input but the operation is missing a requestUri, - * a validation error is thrown. + * Given a shape, finds the Request URI for the operation that references it as input. + * Returns empty if the shape is not a direct operation input. + * Throws if the shape is a direct operation input but the operation is missing a requestUri. + * + * @param parentShape Shape to find operation's request URI for. + * @param allC2jShapes All shapes in the service model. + * @return Request URI for operation, or empty if the shape is not a direct operation input. + * @throws ModelInvalidException If the shape is a direct operation input but requestUri is missing. */ private Optional findRequestUri(Shape parentShape, Map allC2jShapes) { Optional operation = builder.getService().getOperations().values().stream() From 517392f8ea912a4b42f78c4d2e9c83861d0c6703 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Mon, 16 Mar 2026 13:53:47 -0700 Subject: [PATCH 05/11] Ignore HTTP binding locations on non-input shapes per Smithy spec --- .../amazon/awssdk/codegen/AddShapes.java | 29 ++- .../amazon/awssdk/codegen/AddShapesTest.java | 2 +- .../awssdk/codegen/CodeGeneratorTest.java | 21 ++ .../codegen/expected-nested-options.java | 201 ++++++++++++++++++ .../model/nestedqueryparameteroperation.java | 4 +- 5 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 14766b3d46be..a64e1ad15fdf 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -311,8 +311,13 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, ParameterHttpMapping mapping = new ParameterHttpMapping(); + // https://smithy.io/2.0/spec/http-bindings.html#httplabel-is-only-used-on-top-level-input + Location location = isDirectOperationInputOrOutput(parentShape, allC2jShapes) + ? Location.forValue(member.getLocation()) + : null; + Shape memberShape = allC2jShapes.get(member.getShape()); - mapping.withLocation(Location.forValue(member.getLocation())) + mapping.withLocation(location) .withPayload(member.isPayload()).withStreaming(member.isStreaming()) .withFlattened(isFlattened(member, memberShape)) .withUnmarshallLocationName(deriveUnmarshallerLocationName(memberShape, memberName, member)) @@ -323,6 +328,26 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, return mapping; } + private boolean isDirectOperationInputOrOutput(Shape parentShape, Map allC2jShapes) { + for (Operation operation : builder.getService().getOperations().values()) { + if (operation.getInput() != null) { + String inputShapeName = operation.getInput().getShape(); + Shape inputShape = allC2jShapes.get(inputShapeName); + if (parentShape.equals(inputShape)) { + return true; + } + } + if (operation.getOutput() != null) { + String outputShapeName = operation.getOutput().getShape(); + Shape outputShape = allC2jShapes.get(outputShapeName); + if (parentShape.equals(outputShape)) { + return true; + } + } + } + return false; + } + private boolean isFlattened(Member member, Shape memberShape) { return member.isFlattened() || memberShape.isFlattened(); @@ -354,12 +379,10 @@ private boolean isGreedy(Shape parentShape, Map allC2jShapes, Par /** * Given a shape, finds the Request URI for the operation that references it as input. * Returns empty if the shape is not a direct operation input. - * Throws if the shape is a direct operation input but the operation is missing a requestUri. * * @param parentShape Shape to find operation's request URI for. * @param allC2jShapes All shapes in the service model. * @return Request URI for operation, or empty if the shape is not a direct operation input. - * @throws ModelInvalidException If the shape is a direct operation input but requestUri is missing. */ private Optional findRequestUri(Shape parentShape, Map allC2jShapes) { Optional operation = builder.getService().getOperations().values().stream() diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java index dde88dd226e0..5f827cdadd44 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java @@ -84,7 +84,7 @@ void generateShapeModel_memberRequiredByNestedShape_setsMemberModelAsRequired() MemberModel requiredMemberModel = requestShapeModel.findMemberModelByC2jName(queryParamName); assertThat(requestShapeModel.getRequired()).contains(queryParamName); - assertThat(requiredMemberModel.getHttp().getLocation()).isEqualTo(Location.QUERY_STRING); + assertThat(requiredMemberModel.getHttp().getLocation()).isNull(); assertThat(requiredMemberModel.isRequired()).isTrue(); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java index 1f94a8b3849a..c4cc96b16691 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java @@ -44,7 +44,10 @@ import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig; import software.amazon.awssdk.codegen.model.config.customization.UnderscoresInNameBehavior; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.intermediate.MemberModel; +import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.codegen.model.rules.endpoints.EndpointTestSuiteModel; +import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.codegen.model.service.ServiceModel; import software.amazon.awssdk.codegen.poet.ClientTestModels; import software.amazon.awssdk.codegen.validation.ModelInvalidException; @@ -188,6 +191,24 @@ void execute_uriLocationOnNonInputShape_isIgnored() throws IOException { // Per the Smithy spec, httpLabel on non-input shapes has no meaning and is simply ignored. assertThatNoException().isThrownBy( () -> generateCodeFromC2jModels(models, outputDir, true, Collections.emptyList())); + + IntermediateModel intermediateModel = new IntermediateModelBuilder(models).build(); + ShapeModel inputShape = intermediateModel.getShapes().get("SomeOperationRequest"); + MemberModel uriMember = inputShape.findMemberModelByC2jName("thingId"); + assertThat(uriMember.getHttp().getLocation()).isEqualTo(Location.URI); + + ShapeModel nestedShape = intermediateModel.getShapes().get("NestedOptions"); + MemberModel nestedUriMember = nestedShape.findMemberModelByC2jName("pageSize"); + assertThat(nestedUriMember.getHttp().getLocation()).isNull(); + assertThat(nestedUriMember.getHttp().isGreedy()).isFalse(); + + Path generatedNestedOptions = Files.walk(outputDir) + .filter(p -> p.getFileName().toString().equals("NestedOptions.java")) + .findFirst() + .orElseThrow(() -> new AssertionError("NestedOptions.java not found in generated output")); + String actual = new String(Files.readAllBytes(generatedNestedOptions), StandardCharsets.UTF_8); + String expected = resourceAsString("expected-nested-options.java"); + assertThat(actual).isEqualTo(expected); } @Test diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java new file mode 100644 index 000000000000..bb8c7e9e3efc --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java @@ -0,0 +1,201 @@ +/* + * 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.services.restjson.model; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.Mutable; +import software.amazon.awssdk.annotations.NotThreadSafe; +import software.amazon.awssdk.core.SdkField; +import software.amazon.awssdk.core.SdkPojo; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.LocationTrait; +import software.amazon.awssdk.utils.ToString; +import software.amazon.awssdk.utils.builder.CopyableBuilder; +import software.amazon.awssdk.utils.builder.ToCopyableBuilder; + +/** + */ +@Generated("software.amazon.awssdk:codegen") +public final class NestedOptions implements SdkPojo, Serializable, ToCopyableBuilder { + private static final SdkField PAGE_SIZE_FIELD = SdkField. builder(MarshallingType.STRING) + .memberName("pageSize").getter(getter(NestedOptions::pageSize)).setter(setter(Builder::pageSize)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("pageSize").build()).build(); + + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PAGE_SIZE_FIELD)); + + private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); + + private static final long serialVersionUID = 1L; + + private final String pageSize; + + private NestedOptions(BuilderImpl builder) { + this.pageSize = builder.pageSize; + } + + /** + * Returns the value of the PageSize property for this object. + * + * @return The value of the PageSize property for this object. + */ + public final String pageSize() { + return pageSize; + } + + @Override + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static Class serializableBuilderClass() { + return BuilderImpl.class; + } + + @Override + public final int hashCode() { + int hashCode = 1; + hashCode = 31 * hashCode + Objects.hashCode(pageSize()); + return hashCode; + } + + @Override + public final boolean equals(Object obj) { + return equalsBySdkFields(obj); + } + + @Override + public final boolean equalsBySdkFields(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NestedOptions)) { + return false; + } + NestedOptions other = (NestedOptions) obj; + return Objects.equals(pageSize(), other.pageSize()); + } + + /** + * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be + * redacted from this string using a placeholder value. + */ + @Override + public final String toString() { + return ToString.builder("NestedOptions").add("PageSize", pageSize()).build(); + } + + public final Optional getValueForField(String fieldName, Class clazz) { + switch (fieldName) { + case "pageSize": + return Optional.ofNullable(clazz.cast(pageSize())); + default: + return Optional.empty(); + } + } + + @Override + public final List> sdkFields() { + return SDK_FIELDS; + } + + @Override + public final Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; + } + + private static Map> memberNameToFieldInitializer() { + Map> map = new HashMap<>(); + map.put("pageSize", PAGE_SIZE_FIELD); + return Collections.unmodifiableMap(map); + } + + private static Function getter(Function g) { + return obj -> g.apply((NestedOptions) obj); + } + + private static BiConsumer setter(BiConsumer s) { + return (obj, val) -> s.accept((Builder) obj, val); + } + + @Mutable + @NotThreadSafe + public interface Builder extends SdkPojo, CopyableBuilder { + /** + * Sets the value of the PageSize property for this object. + * + * @param pageSize + * The new value for the PageSize property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder pageSize(String pageSize); + } + + static final class BuilderImpl implements Builder { + private String pageSize; + + private BuilderImpl() { + } + + private BuilderImpl(NestedOptions model) { + pageSize(model.pageSize); + } + + public final String getPageSize() { + return pageSize; + } + + public final void setPageSize(String pageSize) { + this.pageSize = pageSize; + } + + @Override + public final Builder pageSize(String pageSize) { + this.pageSize = pageSize; + return this; + } + + @Override + public NestedOptions build() { + return new NestedOptions(this); + } + + @Override + public List> sdkFields() { + return SDK_FIELDS; + } + + @Override + public Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java index c935db9281f0..e743d7c2bea4 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java @@ -33,13 +33,13 @@ public final class NestedQueryParameterOperation implements SdkPojo, Serializabl .memberName("QueryParamOne") .getter(getter(NestedQueryParameterOperation::queryParamOne)) .setter(setter(Builder::queryParamOne)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("QueryParamOne").build(), + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("QueryParamOne").build(), RequiredTrait.create()).build(); private static final SdkField QUERY_PARAM_TWO_FIELD = SdkField. builder(MarshallingType.STRING) .memberName("QueryParamTwo").getter(getter(NestedQueryParameterOperation::queryParamTwo)) .setter(setter(Builder::queryParamTwo)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("QueryParamTwo").build()).build(); + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("QueryParamTwo").build()).build(); private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(QUERY_PARAM_ONE_FIELD, QUERY_PARAM_TWO_FIELD)); From a4cbd8eba015d2e81a046a0fed135233aeb3f266 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:51:00 -0700 Subject: [PATCH 06/11] Account for error shapes as well --- .../software/amazon/awssdk/codegen/AddShapes.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index a64e1ad15fdf..f628c41d8610 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -36,6 +36,7 @@ import software.amazon.awssdk.codegen.model.intermediate.ReturnTypeModel; import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.codegen.model.intermediate.VariableModel; +import software.amazon.awssdk.codegen.model.service.ErrorMap; import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.codegen.model.service.Member; import software.amazon.awssdk.codegen.model.service.Operation; @@ -344,6 +345,16 @@ private boolean isDirectOperationInputOrOutput(Shape parentShape, Map Date: Tue, 17 Mar 2026 14:33:17 -0700 Subject: [PATCH 07/11] Fix comments --- .../amazon/awssdk/codegen/AddShapes.java | 41 +++---- .../amazon/awssdk/codegen/AddShapesTest.java | 16 ++- .../awssdk/codegen/CodeGeneratorTest.java | 11 +- .../codegen/expected-nested-options.java | 102 +++++++++++++++++- .../uri-on-non-input-shape-service.json | 12 ++- 5 files changed, 148 insertions(+), 34 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index f628c41d8610..70d7be7ec3b0 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -22,9 +22,11 @@ import static software.amazon.awssdk.codegen.internal.Utils.isScalar; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import software.amazon.awssdk.codegen.internal.TypeUtils; import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig; import software.amazon.awssdk.codegen.model.intermediate.EnumModel; @@ -55,6 +57,7 @@ abstract class AddShapes { private final IntermediateModelBuilder builder; private final NamingStrategy namingStrategy; + private Set directOperationShapes; AddShapes(IntermediateModelBuilder builder) { this.builder = builder; @@ -313,7 +316,7 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, ParameterHttpMapping mapping = new ParameterHttpMapping(); // https://smithy.io/2.0/spec/http-bindings.html#httplabel-is-only-used-on-top-level-input - Location location = isDirectOperationInputOrOutput(parentShape, allC2jShapes) + Location location = isDirectOperationShape(parentShape, allC2jShapes) ? Location.forValue(member.getLocation()) : null; @@ -329,34 +332,24 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, return mapping; } - private boolean isDirectOperationInputOrOutput(Shape parentShape, Map allC2jShapes) { - for (Operation operation : builder.getService().getOperations().values()) { - if (operation.getInput() != null) { - String inputShapeName = operation.getInput().getShape(); - Shape inputShape = allC2jShapes.get(inputShapeName); - if (parentShape.equals(inputShape)) { - return true; + private boolean isDirectOperationShape(Shape parentShape, Map allC2jShapes) { + if (directOperationShapes == null) { + directOperationShapes = new HashSet<>(); + for (Operation operation : builder.getService().getOperations().values()) { + if (operation.getInput() != null) { + directOperationShapes.add(allC2jShapes.get(operation.getInput().getShape())); } - } - if (operation.getOutput() != null) { - String outputShapeName = operation.getOutput().getShape(); - Shape outputShape = allC2jShapes.get(outputShapeName); - if (parentShape.equals(outputShape)) { - return true; + if (operation.getOutput() != null) { + directOperationShapes.add(allC2jShapes.get(operation.getOutput().getShape())); } - } - - if (operation.getErrors() != null) { - for (ErrorMap error : operation.getErrors()) { - String errorShapeName = error.getShape(); - Shape outputShape = allC2jShapes.get(errorShapeName); - if (parentShape.equals(outputShape)) { - return true; + if (operation.getErrors() != null) { + for (ErrorMap error : operation.getErrors()) { + directOperationShapes.add(allC2jShapes.get(error.getShape())); } } } } - return false; + return directOperationShapes.contains(parentShape); } private boolean isFlattened(Member member, Shape memberShape) { @@ -413,7 +406,7 @@ private Optional findRequestUri(Shape parentShape, Map al .filter(e -> e.getValue().equals(parentShape)) .map(Map.Entry::getKey) .findFirst() - .get(); + .orElseThrow(() -> new IllegalStateException("Shape not found in model: " + parentShape)); String detailMsg = "Could not find request URI for input shape '" + shapeName + "'. No operation was found that references this shape as its input."; ValidationEntry entry = diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java index 5f827cdadd44..0243c001e90e 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java @@ -84,8 +84,22 @@ void generateShapeModel_memberRequiredByNestedShape_setsMemberModelAsRequired() MemberModel requiredMemberModel = requestShapeModel.findMemberModelByC2jName(queryParamName); assertThat(requestShapeModel.getRequired()).contains(queryParamName); - assertThat(requiredMemberModel.getHttp().getLocation()).isNull(); assertThat(requiredMemberModel.isRequired()).isTrue(); } + @Test + void generateShapeModel_locationOnNestedShape_isIgnored() { + ShapeModel nestedShape = intermediateModel.getShapes().get("NestedQueryParameterOperation"); + MemberModel queryParam = nestedShape.findMemberModelByC2jName("QueryParamOne"); + assertThat(queryParam.getHttp().getLocation()).isNull(); + } + + @Test + void generateShapeModel_locationOnDirectInputShape_isPreserved() { + ShapeModel inputShape = intermediateModel.getShapes().get("QueryParameterOperationRequest"); + assertThat(inputShape.findMemberModelByC2jName("PathParam").getHttp().getLocation()).isEqualTo(Location.URI); + assertThat(inputShape.findMemberModelByC2jName("QueryParamOne").getHttp().getLocation()).isEqualTo(Location.QUERY_STRING); + assertThat(inputShape.findMemberModelByC2jName("StringHeaderMember").getHttp().getLocation()).isEqualTo(Location.HEADER); + } + } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java index c4cc96b16691..7da5022cbb83 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java @@ -193,14 +193,15 @@ void execute_uriLocationOnNonInputShape_isIgnored() throws IOException { () -> generateCodeFromC2jModels(models, outputDir, true, Collections.emptyList())); IntermediateModel intermediateModel = new IntermediateModelBuilder(models).build(); + ShapeModel inputShape = intermediateModel.getShapes().get("SomeOperationRequest"); - MemberModel uriMember = inputShape.findMemberModelByC2jName("thingId"); - assertThat(uriMember.getHttp().getLocation()).isEqualTo(Location.URI); + assertThat(inputShape.findMemberModelByC2jName("thingId").getHttp().getLocation()).isEqualTo(Location.URI); ShapeModel nestedShape = intermediateModel.getShapes().get("NestedOptions"); - MemberModel nestedUriMember = nestedShape.findMemberModelByC2jName("pageSize"); - assertThat(nestedUriMember.getHttp().getLocation()).isNull(); - assertThat(nestedUriMember.getHttp().isGreedy()).isFalse(); + assertThat(nestedShape.findMemberModelByC2jName("pageSize").getHttp().getLocation()).isNull(); + assertThat(nestedShape.findMemberModelByC2jName("pageSize").getHttp().isGreedy()).isFalse(); + assertThat(nestedShape.findMemberModelByC2jName("headerParam").getHttp().getLocation()).isNull(); + assertThat(nestedShape.findMemberModelByC2jName("queryParam").getHttp().getLocation()).isNull(); Path generatedNestedOptions = Files.walk(outputDir) .filter(p -> p.getFileName().toString().equals("NestedOptions.java")) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java index bb8c7e9e3efc..8254a9771fa5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java @@ -43,7 +43,17 @@ public final class NestedOptions implements SdkPojo, Serializable, ToCopyableBui .memberName("pageSize").getter(getter(NestedOptions::pageSize)).setter(setter(Builder::pageSize)) .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("pageSize").build()).build(); - private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PAGE_SIZE_FIELD)); + private static final SdkField HEADER_PARAM_FIELD = SdkField. builder(MarshallingType.STRING) + .memberName("headerParam").getter(getter(NestedOptions::headerParam)).setter(setter(Builder::headerParam)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("x-amz-nested-header").build()) + .build(); + + private static final SdkField QUERY_PARAM_FIELD = SdkField. builder(MarshallingType.STRING) + .memberName("queryParam").getter(getter(NestedOptions::queryParam)).setter(setter(Builder::queryParam)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("nestedQuery").build()).build(); + + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PAGE_SIZE_FIELD, + HEADER_PARAM_FIELD, QUERY_PARAM_FIELD)); private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); @@ -51,8 +61,14 @@ public final class NestedOptions implements SdkPojo, Serializable, ToCopyableBui private final String pageSize; + private final String headerParam; + + private final String queryParam; + private NestedOptions(BuilderImpl builder) { this.pageSize = builder.pageSize; + this.headerParam = builder.headerParam; + this.queryParam = builder.queryParam; } /** @@ -64,6 +80,24 @@ public final String pageSize() { return pageSize; } + /** + * Returns the value of the HeaderParam property for this object. + * + * @return The value of the HeaderParam property for this object. + */ + public final String headerParam() { + return headerParam; + } + + /** + * Returns the value of the QueryParam property for this object. + * + * @return The value of the QueryParam property for this object. + */ + public final String queryParam() { + return queryParam; + } + @Override public Builder toBuilder() { return new BuilderImpl(this); @@ -81,6 +115,8 @@ public static Class serializableBuilderClass() { public final int hashCode() { int hashCode = 1; hashCode = 31 * hashCode + Objects.hashCode(pageSize()); + hashCode = 31 * hashCode + Objects.hashCode(headerParam()); + hashCode = 31 * hashCode + Objects.hashCode(queryParam()); return hashCode; } @@ -101,7 +137,8 @@ public final boolean equalsBySdkFields(Object obj) { return false; } NestedOptions other = (NestedOptions) obj; - return Objects.equals(pageSize(), other.pageSize()); + return Objects.equals(pageSize(), other.pageSize()) && Objects.equals(headerParam(), other.headerParam()) + && Objects.equals(queryParam(), other.queryParam()); } /** @@ -110,13 +147,18 @@ public final boolean equalsBySdkFields(Object obj) { */ @Override public final String toString() { - return ToString.builder("NestedOptions").add("PageSize", pageSize()).build(); + return ToString.builder("NestedOptions").add("PageSize", pageSize()).add("HeaderParam", headerParam()) + .add("QueryParam", queryParam()).build(); } public final Optional getValueForField(String fieldName, Class clazz) { switch (fieldName) { case "pageSize": return Optional.ofNullable(clazz.cast(pageSize())); + case "headerParam": + return Optional.ofNullable(clazz.cast(headerParam())); + case "queryParam": + return Optional.ofNullable(clazz.cast(queryParam())); default: return Optional.empty(); } @@ -135,6 +177,8 @@ public final Map> sdkFieldNameToField() { private static Map> memberNameToFieldInitializer() { Map> map = new HashMap<>(); map.put("pageSize", PAGE_SIZE_FIELD); + map.put("x-amz-nested-header", HEADER_PARAM_FIELD); + map.put("nestedQuery", QUERY_PARAM_FIELD); return Collections.unmodifiableMap(map); } @@ -157,16 +201,40 @@ public interface Builder extends SdkPojo, CopyableBuilder Date: Tue, 17 Mar 2026 14:58:05 -0700 Subject: [PATCH 08/11] Fix comments 2 --- .../awssdk/codegen/CodeGeneratorTest.java | 4 + .../codegen/expected-nested-options.java | 88 ++++++++++++++++++- .../uri-on-non-input-shape-service.json | 33 +++++++ 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java index 7da5022cbb83..194a315537b8 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/CodeGeneratorTest.java @@ -202,6 +202,10 @@ void execute_uriLocationOnNonInputShape_isIgnored() throws IOException { assertThat(nestedShape.findMemberModelByC2jName("pageSize").getHttp().isGreedy()).isFalse(); assertThat(nestedShape.findMemberModelByC2jName("headerParam").getHttp().getLocation()).isNull(); assertThat(nestedShape.findMemberModelByC2jName("queryParam").getHttp().getLocation()).isNull(); + assertThat(nestedShape.findMemberModelByC2jName("prefixHeaders").getHttp().getLocation()).isNull(); + + ShapeModel sharedShape = intermediateModel.getShapes().get("SharedShapeOperationRequest"); + assertThat(sharedShape.findMemberModelByC2jName("sharedId").getHttp().getLocation()).isEqualTo(Location.URI); Path generatedNestedOptions = Files.walk(outputDir) .filter(p -> p.getFileName().toString().equals("NestedOptions.java")) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java index 8254a9771fa5..4940bbc56a14 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/expected-nested-options.java @@ -31,6 +31,9 @@ import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.LocationTrait; +import software.amazon.awssdk.core.traits.MapTrait; +import software.amazon.awssdk.core.util.DefaultSdkAutoConstructMap; +import software.amazon.awssdk.core.util.SdkAutoConstructMap; import software.amazon.awssdk.utils.ToString; import software.amazon.awssdk.utils.builder.CopyableBuilder; import software.amazon.awssdk.utils.builder.ToCopyableBuilder; @@ -52,8 +55,22 @@ public final class NestedOptions implements SdkPojo, Serializable, ToCopyableBui .memberName("queryParam").getter(getter(NestedOptions::queryParam)).setter(setter(Builder::queryParam)) .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("nestedQuery").build()).build(); + private static final SdkField> PREFIX_HEADERS_FIELD = SdkField + .> builder(MarshallingType.MAP) + .memberName("prefixHeaders") + .getter(getter(NestedOptions::prefixHeaders)) + .setter(setter(Builder::prefixHeaders)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("x-amz-prefix-").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PAGE_SIZE_FIELD, - HEADER_PARAM_FIELD, QUERY_PARAM_FIELD)); + HEADER_PARAM_FIELD, QUERY_PARAM_FIELD, PREFIX_HEADERS_FIELD)); private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); @@ -65,10 +82,13 @@ public final class NestedOptions implements SdkPojo, Serializable, ToCopyableBui private final String queryParam; + private final Map prefixHeaders; + private NestedOptions(BuilderImpl builder) { this.pageSize = builder.pageSize; this.headerParam = builder.headerParam; this.queryParam = builder.queryParam; + this.prefixHeaders = builder.prefixHeaders; } /** @@ -98,6 +118,34 @@ public final String queryParam() { return queryParam; } + /** + * For responses, this returns true if the service returned a value for the PrefixHeaders property. This DOES NOT + * check that the value is non-empty (for which, you should check the {@code isEmpty()} method on the property). + * This is useful because the SDK will never return a null collection or map, but you may need to differentiate + * between the service returning nothing (or null) and the service returning an empty collection or map. For + * requests, this returns true if a value for the property was specified in the request builder, and false if a + * value was not specified. + */ + public final boolean hasPrefixHeaders() { + return prefixHeaders != null && !(prefixHeaders instanceof SdkAutoConstructMap); + } + + /** + * Returns the value of the PrefixHeaders property for this object. + *

+ * Attempts to modify the collection returned by this method will result in an UnsupportedOperationException. + *

+ *

+ * This method will never return null. If you would like to know whether the service returned this field (so that + * you can differentiate between null and empty), you can use the {@link #hasPrefixHeaders} method. + *

+ * + * @return The value of the PrefixHeaders property for this object. + */ + public final Map prefixHeaders() { + return prefixHeaders; + } + @Override public Builder toBuilder() { return new BuilderImpl(this); @@ -117,6 +165,7 @@ public final int hashCode() { hashCode = 31 * hashCode + Objects.hashCode(pageSize()); hashCode = 31 * hashCode + Objects.hashCode(headerParam()); hashCode = 31 * hashCode + Objects.hashCode(queryParam()); + hashCode = 31 * hashCode + Objects.hashCode(hasPrefixHeaders() ? prefixHeaders() : null); return hashCode; } @@ -138,7 +187,8 @@ public final boolean equalsBySdkFields(Object obj) { } NestedOptions other = (NestedOptions) obj; return Objects.equals(pageSize(), other.pageSize()) && Objects.equals(headerParam(), other.headerParam()) - && Objects.equals(queryParam(), other.queryParam()); + && Objects.equals(queryParam(), other.queryParam()) && hasPrefixHeaders() == other.hasPrefixHeaders() + && Objects.equals(prefixHeaders(), other.prefixHeaders()); } /** @@ -148,7 +198,7 @@ public final boolean equalsBySdkFields(Object obj) { @Override public final String toString() { return ToString.builder("NestedOptions").add("PageSize", pageSize()).add("HeaderParam", headerParam()) - .add("QueryParam", queryParam()).build(); + .add("QueryParam", queryParam()).add("PrefixHeaders", hasPrefixHeaders() ? prefixHeaders() : null).build(); } public final Optional getValueForField(String fieldName, Class clazz) { @@ -159,6 +209,8 @@ public final Optional getValueForField(String fieldName, Class clazz) return Optional.ofNullable(clazz.cast(headerParam())); case "queryParam": return Optional.ofNullable(clazz.cast(queryParam())); + case "prefixHeaders": + return Optional.ofNullable(clazz.cast(prefixHeaders())); default: return Optional.empty(); } @@ -179,6 +231,7 @@ private static Map> memberNameToFieldInitializer() { map.put("pageSize", PAGE_SIZE_FIELD); map.put("x-amz-nested-header", HEADER_PARAM_FIELD); map.put("nestedQuery", QUERY_PARAM_FIELD); + map.put("x-amz-prefix-", PREFIX_HEADERS_FIELD); return Collections.unmodifiableMap(map); } @@ -219,6 +272,15 @@ public interface Builder extends SdkPojo, CopyableBuilder prefixHeaders); } static final class BuilderImpl implements Builder { @@ -228,6 +290,8 @@ static final class BuilderImpl implements Builder { private String queryParam; + private Map prefixHeaders = DefaultSdkAutoConstructMap.getInstance(); + private BuilderImpl() { } @@ -235,6 +299,7 @@ private BuilderImpl(NestedOptions model) { pageSize(model.pageSize); headerParam(model.headerParam); queryParam(model.queryParam); + prefixHeaders(model.prefixHeaders); } public final String getPageSize() { @@ -279,6 +344,23 @@ public final Builder queryParam(String queryParam) { return this; } + public final Map getPrefixHeaders() { + if (prefixHeaders instanceof SdkAutoConstructMap) { + return null; + } + return prefixHeaders; + } + + public final void setPrefixHeaders(Map prefixHeaders) { + this.prefixHeaders = MapOfStringsCopier.copy(prefixHeaders); + } + + @Override + public final Builder prefixHeaders(Map prefixHeaders) { + this.prefixHeaders = MapOfStringsCopier.copy(prefixHeaders); + return this; + } + @Override public NestedOptions build() { return new NestedOptions(this); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json index 08357e6e89b2..f858a11b94ed 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/uri-on-non-input-shape-service.json @@ -23,6 +23,16 @@ "input": { "shape": "SomeOperationRequest" } + }, + "SharedShapeOperation": { + "name": "SharedShapeOperation", + "http": { + "method": "GET", + "requestUri": "/shared/{sharedId}" + }, + "input": { + "shape": "SharedShape" + } } }, "shapes": { @@ -36,6 +46,9 @@ }, "options": { "shape": "NestedOptions" + }, + "shared": { + "shape": "SharedShape" } } }, @@ -56,11 +69,31 @@ "shape": "String", "location": "querystring", "locationName": "nestedQuery" + }, + "prefixHeaders": { + "shape": "MapOfStrings", + "location": "headers", + "locationName": "x-amz-prefix-" + } + } + }, + "SharedShape": { + "type": "structure", + "members": { + "sharedId": { + "shape": "String", + "location": "uri", + "locationName": "sharedId" } } }, "String": { "type": "string" + }, + "MapOfStrings": { + "type": "map", + "key": {"shape": "String"}, + "value": {"shape": "String"} } }, "documentation": "A service with HTTP binding locations on non-input shapes" From c4a79f0233288960c3c157877d34c6ab2b96f814 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:53:34 -0700 Subject: [PATCH 09/11] Add assertion --- .../src/main/java/software/amazon/awssdk/codegen/AddShapes.java | 2 +- .../test/java/software/amazon/awssdk/codegen/AddShapesTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index 70d7be7ec3b0..a965a12f5f29 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -315,7 +315,7 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, ParameterHttpMapping mapping = new ParameterHttpMapping(); - // https://smithy.io/2.0/spec/http-bindings.html#httplabel-is-only-used-on-top-level-input + // https://smithy.io/2.0/spec/http-bindings.html Location location = isDirectOperationShape(parentShape, allC2jShapes) ? Location.forValue(member.getLocation()) : null; diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java index 0243c001e90e..45185281666c 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/AddShapesTest.java @@ -84,6 +84,7 @@ void generateShapeModel_memberRequiredByNestedShape_setsMemberModelAsRequired() MemberModel requiredMemberModel = requestShapeModel.findMemberModelByC2jName(queryParamName); assertThat(requestShapeModel.getRequired()).contains(queryParamName); + assertThat(requiredMemberModel.getHttp().getLocation()).isNull(); assertThat(requiredMemberModel.isRequired()).isTrue(); } From 302c2958caf72519d094d3bcda844b61bb41aa2d Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:14:00 -0700 Subject: [PATCH 10/11] Add protocol test --- .../codegen-resources/restjson/service-2.json | 30 ++++++++ .../NestedLocationSerializationTest.java | 76 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/NestedLocationSerializationTest.java diff --git a/test/protocol-tests/src/main/resources/codegen-resources/restjson/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/restjson/service-2.json index c0348f5b1ca6..70e58cf31d0d 100644 --- a/test/protocol-tests/src/main/resources/codegen-resources/restjson/service-2.json +++ b/test/protocol-tests/src/main/resources/codegen-resources/restjson/service-2.json @@ -255,6 +255,14 @@ "requestUri":"/2016-03-11/documentInputOperation" }, "input":{"shape":"StructureWithDocumentMember"} + }, + "NestedLocationOperation":{ + "name":"NestedLocationOperation", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/nestedLocationOperation" + }, + "input":{"shape":"NestedLocationOperationInput"} } }, "shapes":{ @@ -782,6 +790,28 @@ "StringMember":{"shape":"String"} } }, + "NestedLocationOperationInput":{ + "type":"structure", + "members":{ + "TopLevelQueryParam":{ + "shape":"String", + "location":"querystring", + "locationName":"topLevel" + }, + "Nested":{"shape":"NestedShapeWithLocations"} + } + }, + "NestedShapeWithLocations":{ + "type":"structure", + "members":{ + "NestedQueryParam":{ + "shape":"String", + "location":"querystring", + "locationName":"shouldBeIgnored" + }, + "StringMember":{"shape":"String"} + } + }, "StatusCodeInOutputStructure":{ "type":"structure", "members":{ diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/NestedLocationSerializationTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/NestedLocationSerializationTest.java new file mode 100644 index 000000000000..da25133f45b2 --- /dev/null +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/NestedLocationSerializationTest.java @@ -0,0 +1,76 @@ +/* + * 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.protocol.tests; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.net.URI; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient; +import software.amazon.awssdk.services.protocolrestjson.model.NestedLocationOperationRequest; +import software.amazon.awssdk.services.protocolrestjson.model.NestedShapeWithLocations; + +/** + * Verifies that HTTP binding locations on non-input shapes are ignored per the Smithy spec, + * and the members are serialized into the request body instead. + */ +public class NestedLocationSerializationTest { + + @Rule + public WireMockRule wireMock = new WireMockRule(0); + + private ProtocolRestJsonClient client; + + @Before + public void setup() { + client = ProtocolRestJsonClient.builder() + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))) + .region(Region.US_EAST_1) + .endpointOverride(URI.create("http://localhost:" + wireMock.port())) + .build(); + } + + @Test + public void nestedMemberWithLocation_serializedToBodyNotQueryParam() { + stubFor(post(anyUrl()).willReturn(aResponse().withStatus(200).withBody("{}"))); + + client.nestedLocationOperation(NestedLocationOperationRequest.builder() + .topLevelQueryParam("topValue") + .nested(NestedShapeWithLocations.builder() + .nestedQueryParam("nestedValue") + .stringMember("hello") + .build()) + .build()); + + verify(postRequestedFor(anyUrl()).withQueryParam("topLevel", equalTo("topValue"))); + + verify(postRequestedFor(anyUrl()).withRequestBody( + equalToJson("{\"Nested\":{\"shouldBeIgnored\":\"nestedValue\",\"StringMember\":\"hello\"}}"))); + } +} From 7567ffa6b227e76835c447622ae48f6acd3ac060 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:25:40 -0700 Subject: [PATCH 11/11] Refadctor to remove cache complexity, add coverage --- .../amazon/awssdk/codegen/AddShapes.java | 66 +- .../model/nestedqueryparameteroperation.java | 430 ++++--- .../model/queryparameteroperationrequest.java | 1089 ++++++++--------- .../queryparameteroperationresponse.java | 349 ++++-- .../awssdk/codegen/poet/model/service-2.json | 40 +- 5 files changed, 1159 insertions(+), 815 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java index a965a12f5f29..9944a6a52931 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java @@ -22,11 +22,9 @@ import static software.amazon.awssdk.codegen.internal.Utils.isScalar; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import software.amazon.awssdk.codegen.internal.TypeUtils; import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig; import software.amazon.awssdk.codegen.model.intermediate.EnumModel; @@ -38,7 +36,6 @@ import software.amazon.awssdk.codegen.model.intermediate.ReturnTypeModel; import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.codegen.model.intermediate.VariableModel; -import software.amazon.awssdk.codegen.model.service.ErrorMap; import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.codegen.model.service.Member; import software.amazon.awssdk.codegen.model.service.Operation; @@ -57,7 +54,6 @@ abstract class AddShapes { private final IntermediateModelBuilder builder; private final NamingStrategy namingStrategy; - private Set directOperationShapes; AddShapes(IntermediateModelBuilder builder) { this.builder = builder; @@ -315,10 +311,9 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, ParameterHttpMapping mapping = new ParameterHttpMapping(); + // Per the Smithy spec, HTTP binding traits are only honored on specific shape types: // https://smithy.io/2.0/spec/http-bindings.html - Location location = isDirectOperationShape(parentShape, allC2jShapes) - ? Location.forValue(member.getLocation()) - : null; + Location location = resolveLocation(parentShape, member, allC2jShapes); Shape memberShape = allC2jShapes.get(member.getShape()); mapping.withLocation(location) @@ -332,24 +327,43 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape, return mapping; } - private boolean isDirectOperationShape(Shape parentShape, Map allC2jShapes) { - if (directOperationShapes == null) { - directOperationShapes = new HashSet<>(); - for (Operation operation : builder.getService().getOperations().values()) { - if (operation.getInput() != null) { - directOperationShapes.add(allC2jShapes.get(operation.getInput().getShape())); - } - if (operation.getOutput() != null) { - directOperationShapes.add(allC2jShapes.get(operation.getOutput().getShape())); - } - if (operation.getErrors() != null) { - for (ErrorMap error : operation.getErrors()) { - directOperationShapes.add(allC2jShapes.get(error.getShape())); - } - } - } + private Location resolveLocation(Shape parentShape, Member member, Map allC2jShapes) { + Location location = Location.forValue(member.getLocation()); + if (location == null) { + return null; + } + switch (location) { + case URI: + case QUERY_STRING: + return isDirectInputShape(parentShape, allC2jShapes) ? location : null; + case HEADER: + case HEADERS: + return isDirectOperationShape(parentShape, allC2jShapes) ? location : null; + case STATUS_CODE: + return isDirectOutputShape(parentShape, allC2jShapes) ? location : null; + default: + return location; } - return directOperationShapes.contains(parentShape); + } + + private boolean isDirectInputShape(Shape shape, Map allC2jShapes) { + return builder.getService().getOperations().values().stream() + .filter(o -> o.getInput() != null) + .anyMatch(o -> allC2jShapes.get(o.getInput().getShape()).equals(shape)); + } + + private boolean isDirectOutputShape(Shape shape, Map allC2jShapes) { + return builder.getService().getOperations().values().stream() + .filter(o -> o.getOutput() != null) + .anyMatch(o -> allC2jShapes.get(o.getOutput().getShape()).equals(shape)); + } + + private boolean isDirectOperationShape(Shape shape, Map allC2jShapes) { + return builder.getService().getOperations().values().stream() + .anyMatch(o -> (o.getInput() != null && allC2jShapes.get(o.getInput().getShape()).equals(shape)) + || (o.getOutput() != null && allC2jShapes.get(o.getOutput().getShape()).equals(shape)) + || (o.getErrors() != null && o.getErrors().stream() + .anyMatch(e -> allC2jShapes.get(e.getShape()).equals(shape)))); } private boolean isFlattened(Member member, Shape memberShape) { @@ -407,8 +421,8 @@ private Optional findRequestUri(Shape parentShape, Map al .map(Map.Entry::getKey) .findFirst() .orElseThrow(() -> new IllegalStateException("Shape not found in model: " + parentShape)); - String detailMsg = "Could not find request URI for input shape '" + shapeName - + "'. No operation was found that references this shape as its input."; + String detailMsg = "Operation referencing input shape '" + shapeName + + "' has no requestUri configured in its HTTP binding."; ValidationEntry entry = new ValidationEntry().withErrorId(ValidationErrorId.REQUEST_URI_NOT_FOUND) .withDetailMessage(detailMsg) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java index e743d7c2bea4..611656500dd2 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/nestedqueryparameteroperation.java @@ -26,218 +26,308 @@ /** */ @Generated("software.amazon.awssdk:codegen") -public final class NestedQueryParameterOperation implements SdkPojo, Serializable, - ToCopyableBuilder { - private static final SdkField QUERY_PARAM_ONE_FIELD = SdkField - . builder(MarshallingType.STRING) - .memberName("QueryParamOne") - .getter(getter(NestedQueryParameterOperation::queryParamOne)) - .setter(setter(Builder::queryParamOne)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("QueryParamOne").build(), - RequiredTrait.create()).build(); - - private static final SdkField QUERY_PARAM_TWO_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("QueryParamTwo").getter(getter(NestedQueryParameterOperation::queryParamTwo)) - .setter(setter(Builder::queryParamTwo)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("QueryParamTwo").build()).build(); - - private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(QUERY_PARAM_ONE_FIELD, - QUERY_PARAM_TWO_FIELD)); - - private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); - - private static final long serialVersionUID = 1L; - - private final String queryParamOne; - - private final String queryParamTwo; - - private NestedQueryParameterOperation(BuilderImpl builder) { - this.queryParamOne = builder.queryParamOne; - this.queryParamTwo = builder.queryParamTwo; +public final class NestedQueryParameterOperation implements SdkPojo, Serializable, ToCopyableBuilder { + private static final SdkField QUERY_PARAM_ONE_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("QueryParamOne") + .getter(getter(NestedQueryParameterOperation::queryParamOne)) + .setter(setter(Builder::queryParamOne)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("QueryParamOne") + .build(), RequiredTrait.create()).build(); + + private static final SdkField QUERY_PARAM_TWO_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("QueryParamTwo") + .getter(getter(NestedQueryParameterOperation::queryParamTwo)) + .setter(setter(Builder::queryParamTwo)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("QueryParamTwo") + .build()).build(); + + private static final SdkField NESTED_HEADER_MEMBER_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("NestedHeaderMember") + .getter(getter(NestedQueryParameterOperation::nestedHeaderMember)) + .setter(setter(Builder::nestedHeaderMember)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("x-amz-nested-header") + .build()).build(); + + private static final SdkField NESTED_STATUS_CODE_FIELD = SdkField.builder(MarshallingType.INTEGER) + .memberName("NestedStatusCode") + .getter(getter(NestedQueryParameterOperation::nestedStatusCode)) + .setter(setter(Builder::nestedStatusCode)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("NestedStatusCode") + .build()).build(); + + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(QUERY_PARAM_ONE_FIELD,QUERY_PARAM_TWO_FIELD,NESTED_HEADER_MEMBER_FIELD,NESTED_STATUS_CODE_FIELD)); + + private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); + + private static final long serialVersionUID = 1L; + + private final String queryParamOne; + + private final String queryParamTwo; + + private final String nestedHeaderMember; + + private final Integer nestedStatusCode; + + private NestedQueryParameterOperation(BuilderImpl builder) { + this.queryParamOne = builder.queryParamOne; + this.queryParamTwo = builder.queryParamTwo; + this.nestedHeaderMember = builder.nestedHeaderMember; + this.nestedStatusCode = builder.nestedStatusCode; + } + + /** + * Returns the value of the QueryParamOne property for this object. + * @return The value of the QueryParamOne property for this object. + */ + public final String queryParamOne() { + return queryParamOne; + } + + /** + * Returns the value of the QueryParamTwo property for this object. + * @return The value of the QueryParamTwo property for this object. + */ + public final String queryParamTwo() { + return queryParamTwo; + } + + /** + * Returns the value of the NestedHeaderMember property for this object. + * @return The value of the NestedHeaderMember property for this object. + */ + public final String nestedHeaderMember() { + return nestedHeaderMember; + } + + /** + * Returns the value of the NestedStatusCode property for this object. + * @return The value of the NestedStatusCode property for this object. + */ + public final Integer nestedStatusCode() { + return nestedStatusCode; + } + + @Override + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static Class serializableBuilderClass() { + return BuilderImpl.class; + } + + @Override + public final int hashCode() { + int hashCode = 1; + hashCode = 31 * hashCode + Objects.hashCode(queryParamOne()); + hashCode = 31 * hashCode + Objects.hashCode(queryParamTwo()); + hashCode = 31 * hashCode + Objects.hashCode(nestedHeaderMember()); + hashCode = 31 * hashCode + Objects.hashCode(nestedStatusCode()); + return hashCode; + } + + @Override + public final boolean equals(Object obj) { + return equalsBySdkFields(obj); + } + + @Override + public final boolean equalsBySdkFields(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof NestedQueryParameterOperation)) { + return false; } + NestedQueryParameterOperation other = (NestedQueryParameterOperation) obj; + return Objects.equals(queryParamOne(), other.queryParamOne())&&Objects.equals(queryParamTwo(), other.queryParamTwo())&&Objects.equals(nestedHeaderMember(), other.nestedHeaderMember())&&Objects.equals(nestedStatusCode(), other.nestedStatusCode()); + } + + /** + * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be redacted from this string using a placeholder value. + */ + @Override + public final String toString() { + return ToString.builder("NestedQueryParameterOperation").add("QueryParamOne", queryParamOne()).add("QueryParamTwo", queryParamTwo()).add("NestedHeaderMember", nestedHeaderMember()).add("NestedStatusCode", nestedStatusCode()).build(); + } + + public final Optional getValueForField(String fieldName, Class clazz) { + switch (fieldName) { + case "QueryParamOne":return Optional.ofNullable(clazz.cast(queryParamOne())); + case "QueryParamTwo":return Optional.ofNullable(clazz.cast(queryParamTwo())); + case "NestedHeaderMember":return Optional.ofNullable(clazz.cast(nestedHeaderMember())); + case "NestedStatusCode":return Optional.ofNullable(clazz.cast(nestedStatusCode())); + default:return Optional.empty(); + } + } + + @Override + public final List> sdkFields() { + return SDK_FIELDS; + } + + @Override + public final Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; + } + + private static Map> memberNameToFieldInitializer() { + Map> map = new HashMap<>(); + map.put("QueryParamOne", QUERY_PARAM_ONE_FIELD); + map.put("QueryParamTwo", QUERY_PARAM_TWO_FIELD); + map.put("x-amz-nested-header", NESTED_HEADER_MEMBER_FIELD); + map.put("NestedStatusCode", NESTED_STATUS_CODE_FIELD); + return Collections.unmodifiableMap(map); + } + + private static Function getter(Function g) { + return obj -> g.apply((NestedQueryParameterOperation) obj); + } + + private static BiConsumer setter(BiConsumer s) { + return (obj, val) -> s.accept((Builder) obj, val); + } + + @Mutable + @NotThreadSafe + public interface Builder extends SdkPojo, CopyableBuilder { + /** + * Sets the value of the QueryParamOne property for this object. + * + * @param queryParamOne The new value for the QueryParamOne property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder queryParamOne(String queryParamOne); /** - * Returns the value of the QueryParamOne property for this object. + * Sets the value of the QueryParamTwo property for this object. * - * @return The value of the QueryParamOne property for this object. + * @param queryParamTwo The new value for the QueryParamTwo property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String queryParamOne() { - return queryParamOne; - } + Builder queryParamTwo(String queryParamTwo); + + /** + * Sets the value of the NestedHeaderMember property for this object. + * + * @param nestedHeaderMember The new value for the NestedHeaderMember property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder nestedHeaderMember(String nestedHeaderMember); /** - * Returns the value of the QueryParamTwo property for this object. + * Sets the value of the NestedStatusCode property for this object. * - * @return The value of the QueryParamTwo property for this object. + * @param nestedStatusCode The new value for the NestedStatusCode property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String queryParamTwo() { - return queryParamTwo; + Builder nestedStatusCode(Integer nestedStatusCode); + } + + static final class BuilderImpl implements Builder { + private String queryParamOne; + + private String queryParamTwo; + + private String nestedHeaderMember; + + private Integer nestedStatusCode; + + private BuilderImpl() { } - @Override - public Builder toBuilder() { - return new BuilderImpl(this); + private BuilderImpl(NestedQueryParameterOperation model) { + queryParamOne(model.queryParamOne); + queryParamTwo(model.queryParamTwo); + nestedHeaderMember(model.nestedHeaderMember); + nestedStatusCode(model.nestedStatusCode); } - public static Builder builder() { - return new BuilderImpl(); + public final String getQueryParamOne() { + return queryParamOne; } - public static Class serializableBuilderClass() { - return BuilderImpl.class; + public final void setQueryParamOne(String queryParamOne) { + this.queryParamOne = queryParamOne; } @Override - public final int hashCode() { - int hashCode = 1; - hashCode = 31 * hashCode + Objects.hashCode(queryParamOne()); - hashCode = 31 * hashCode + Objects.hashCode(queryParamTwo()); - return hashCode; + public final Builder queryParamOne(String queryParamOne) { + this.queryParamOne = queryParamOne; + return this; } - @Override - public final boolean equals(Object obj) { - return equalsBySdkFields(obj); + public final String getQueryParamTwo() { + return queryParamTwo; } - @Override - public final boolean equalsBySdkFields(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof NestedQueryParameterOperation)) { - return false; - } - NestedQueryParameterOperation other = (NestedQueryParameterOperation) obj; - return Objects.equals(queryParamOne(), other.queryParamOne()) && Objects.equals(queryParamTwo(), other.queryParamTwo()); + public final void setQueryParamTwo(String queryParamTwo) { + this.queryParamTwo = queryParamTwo; } - /** - * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be - * redacted from this string using a placeholder value. - */ @Override - public final String toString() { - return ToString.builder("NestedQueryParameterOperation").add("QueryParamOne", queryParamOne()) - .add("QueryParamTwo", queryParamTwo()).build(); + public final Builder queryParamTwo(String queryParamTwo) { + this.queryParamTwo = queryParamTwo; + return this; } - public final Optional getValueForField(String fieldName, Class clazz) { - switch (fieldName) { - case "QueryParamOne": - return Optional.ofNullable(clazz.cast(queryParamOne())); - case "QueryParamTwo": - return Optional.ofNullable(clazz.cast(queryParamTwo())); - default: - return Optional.empty(); - } + public final String getNestedHeaderMember() { + return nestedHeaderMember; } - @Override - public final List> sdkFields() { - return SDK_FIELDS; + public final void setNestedHeaderMember(String nestedHeaderMember) { + this.nestedHeaderMember = nestedHeaderMember; } @Override - public final Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; + public final Builder nestedHeaderMember(String nestedHeaderMember) { + this.nestedHeaderMember = nestedHeaderMember; + return this; } - private static Map> memberNameToFieldInitializer() { - Map> map = new HashMap<>(); - map.put("QueryParamOne", QUERY_PARAM_ONE_FIELD); - map.put("QueryParamTwo", QUERY_PARAM_TWO_FIELD); - return Collections.unmodifiableMap(map); + public final Integer getNestedStatusCode() { + return nestedStatusCode; } - private static Function getter(Function g) { - return obj -> g.apply((NestedQueryParameterOperation) obj); + public final void setNestedStatusCode(Integer nestedStatusCode) { + this.nestedStatusCode = nestedStatusCode; } - private static BiConsumer setter(BiConsumer s) { - return (obj, val) -> s.accept((Builder) obj, val); + @Override + public final Builder nestedStatusCode(Integer nestedStatusCode) { + this.nestedStatusCode = nestedStatusCode; + return this; } - @Mutable - @NotThreadSafe - public interface Builder extends SdkPojo, CopyableBuilder { - /** - * Sets the value of the QueryParamOne property for this object. - * - * @param queryParamOne - * The new value for the QueryParamOne property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder queryParamOne(String queryParamOne); - - /** - * Sets the value of the QueryParamTwo property for this object. - * - * @param queryParamTwo - * The new value for the QueryParamTwo property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder queryParamTwo(String queryParamTwo); + @Override + public NestedQueryParameterOperation build() { + return new NestedQueryParameterOperation(this); } - static final class BuilderImpl implements Builder { - private String queryParamOne; - - private String queryParamTwo; - - private BuilderImpl() { - } - - private BuilderImpl(NestedQueryParameterOperation model) { - queryParamOne(model.queryParamOne); - queryParamTwo(model.queryParamTwo); - } - - public final String getQueryParamOne() { - return queryParamOne; - } - - public final void setQueryParamOne(String queryParamOne) { - this.queryParamOne = queryParamOne; - } - - @Override - public final Builder queryParamOne(String queryParamOne) { - this.queryParamOne = queryParamOne; - return this; - } - - public final String getQueryParamTwo() { - return queryParamTwo; - } - - public final void setQueryParamTwo(String queryParamTwo) { - this.queryParamTwo = queryParamTwo; - } - - @Override - public final Builder queryParamTwo(String queryParamTwo) { - this.queryParamTwo = queryParamTwo; - return this; - } - - @Override - public NestedQueryParameterOperation build() { - return new NestedQueryParameterOperation(this); - } - - @Override - public List> sdkFields() { - return SDK_FIELDS; - } + @Override + public List> sdkFields() { + return SDK_FIELDS; + } - @Override - public Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; - } + @Override + public Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; } + } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationrequest.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationrequest.java index 6e5452cb2e58..74c7c9899ac8 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationrequest.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationrequest.java @@ -32,614 +32,607 @@ /** */ @Generated("software.amazon.awssdk:codegen") -public final class QueryParameterOperationRequest extends JsonProtocolTestsRequest implements - ToCopyableBuilder { - private static final SdkField PATH_PARAM_FIELD = SdkField - . builder(MarshallingType.STRING) - .memberName("PathParam") - .getter(getter(QueryParameterOperationRequest::pathParam)) - .setter(setter(Builder::pathParam)) - .traits(LocationTrait.builder().location(MarshallLocation.PATH).locationName("PathParam").build(), - RequiredTrait.create()).build(); - - private static final SdkField QUERY_PARAM_ONE_FIELD = SdkField - . builder(MarshallingType.STRING) - .memberName("QueryParamOne") - .getter(getter(QueryParameterOperationRequest::queryParamOne)) - .setter(setter(Builder::queryParamOne)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("QueryParamOne").build(), - RequiredTrait.create()).build(); - - private static final SdkField QUERY_PARAM_TWO_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("QueryParamTwo").getter(getter(QueryParameterOperationRequest::queryParamTwo)) - .setter(setter(Builder::queryParamTwo)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("QueryParamTwo").build()).build(); - - private static final SdkField STRING_HEADER_MEMBER_FIELD = SdkField - . builder(MarshallingType.STRING) - .memberName("StringHeaderMember") - .getter(getter(QueryParameterOperationRequest::stringHeaderMember)) - .setter(setter(Builder::stringHeaderMember)) - .traits(LocationTrait.builder().location(MarshallLocation.HEADER).locationName("x-amz-header-string").build(), - RequiredTrait.create()).build(); - - private static final SdkField NESTED_QUERY_PARAMETER_OPERATION_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("NestedQueryParameterOperation") - .getter(getter(QueryParameterOperationRequest::nestedQueryParameterOperation)) - .setter(setter(Builder::nestedQueryParameterOperation)) - .constructor(NestedQueryParameterOperation::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("NestedQueryParameterOperation") - .build(), PayloadTrait.create()).build(); - - private static final SdkField> REQUIRED_LIST_QUERY_PARAMS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("RequiredListQueryParams") - .getter(getter(QueryParameterOperationRequest::requiredListQueryParams)) - .setter(setter(Builder::requiredListQueryParams)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("RequiredListQueryParams") - .build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.INTEGER) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build(), RequiredTrait.create()) - .build(); - - private static final SdkField> OPTIONAL_LIST_QUERY_PARAMS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("OptionalListQueryParams") - .getter(getter(QueryParameterOperationRequest::optionalListQueryParams)) - .setter(setter(Builder::optionalListQueryParams)) - .traits(LocationTrait.builder().location(MarshallLocation.QUERY_PARAM).locationName("OptionalListQueryParams") - .build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.INTEGER) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); - - private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PATH_PARAM_FIELD, - QUERY_PARAM_ONE_FIELD, QUERY_PARAM_TWO_FIELD, STRING_HEADER_MEMBER_FIELD, NESTED_QUERY_PARAMETER_OPERATION_FIELD, - REQUIRED_LIST_QUERY_PARAMS_FIELD, OPTIONAL_LIST_QUERY_PARAMS_FIELD)); - - private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); - - private final String pathParam; - - private final String queryParamOne; - - private final String queryParamTwo; - - private final String stringHeaderMember; - - private final NestedQueryParameterOperation nestedQueryParameterOperation; - - private final List requiredListQueryParams; - - private final List optionalListQueryParams; - - private QueryParameterOperationRequest(BuilderImpl builder) { - super(builder); - this.pathParam = builder.pathParam; - this.queryParamOne = builder.queryParamOne; - this.queryParamTwo = builder.queryParamTwo; - this.stringHeaderMember = builder.stringHeaderMember; - this.nestedQueryParameterOperation = builder.nestedQueryParameterOperation; - this.requiredListQueryParams = builder.requiredListQueryParams; - this.optionalListQueryParams = builder.optionalListQueryParams; +public final class QueryParameterOperationRequest extends JsonProtocolTestsRequest implements ToCopyableBuilder { + private static final SdkField PATH_PARAM_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("PathParam") + .getter(getter(QueryParameterOperationRequest::pathParam)) + .setter(setter(Builder::pathParam)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PATH) + .locationName("PathParam") + .build(), RequiredTrait.create()).build(); + + private static final SdkField QUERY_PARAM_ONE_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("QueryParamOne") + .getter(getter(QueryParameterOperationRequest::queryParamOne)) + .setter(setter(Builder::queryParamOne)) + .traits(LocationTrait.builder() + .location(MarshallLocation.QUERY_PARAM) + .locationName("QueryParamOne") + .build(), RequiredTrait.create()).build(); + + private static final SdkField QUERY_PARAM_TWO_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("QueryParamTwo") + .getter(getter(QueryParameterOperationRequest::queryParamTwo)) + .setter(setter(Builder::queryParamTwo)) + .traits(LocationTrait.builder() + .location(MarshallLocation.QUERY_PARAM) + .locationName("QueryParamTwo") + .build()).build(); + + private static final SdkField STRING_HEADER_MEMBER_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("StringHeaderMember") + .getter(getter(QueryParameterOperationRequest::stringHeaderMember)) + .setter(setter(Builder::stringHeaderMember)) + .traits(LocationTrait.builder() + .location(MarshallLocation.HEADER) + .locationName("x-amz-header-string") + .build(), RequiredTrait.create()).build(); + + private static final SdkField NESTED_QUERY_PARAMETER_OPERATION_FIELD = SdkField.builder(MarshallingType.SDK_POJO) + .memberName("NestedQueryParameterOperation") + .getter(getter(QueryParameterOperationRequest::nestedQueryParameterOperation)) + .setter(setter(Builder::nestedQueryParameterOperation)) + .constructor(NestedQueryParameterOperation::builder) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("NestedQueryParameterOperation") + .build(), PayloadTrait.create()).build(); + + private static final SdkField> REQUIRED_LIST_QUERY_PARAMS_FIELD = SdkField.>builder(MarshallingType.LIST) + .memberName("RequiredListQueryParams") + .getter(getter(QueryParameterOperationRequest::requiredListQueryParams)) + .setter(setter(Builder::requiredListQueryParams)) + .traits(LocationTrait.builder() + .location(MarshallLocation.QUERY_PARAM) + .locationName("RequiredListQueryParams") + .build(), ListTrait.builder() + .memberLocationName(null) + .memberFieldInfo(SdkField.builder(MarshallingType.INTEGER) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member") + .build()).build()) + .build(), RequiredTrait.create()).build(); + + private static final SdkField> OPTIONAL_LIST_QUERY_PARAMS_FIELD = SdkField.>builder(MarshallingType.LIST) + .memberName("OptionalListQueryParams") + .getter(getter(QueryParameterOperationRequest::optionalListQueryParams)) + .setter(setter(Builder::optionalListQueryParams)) + .traits(LocationTrait.builder() + .location(MarshallLocation.QUERY_PARAM) + .locationName("OptionalListQueryParams") + .build(), ListTrait.builder() + .memberLocationName(null) + .memberFieldInfo(SdkField.builder(MarshallingType.INTEGER) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member") + .build()).build()) + .build()).build(); + + private static final SdkField STATUS_CODE_ON_INPUT_FIELD = SdkField.builder(MarshallingType.INTEGER) + .memberName("StatusCodeOnInput") + .getter(getter(QueryParameterOperationRequest::statusCodeOnInput)) + .setter(setter(Builder::statusCodeOnInput)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("StatusCodeOnInput") + .build()).build(); + + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(PATH_PARAM_FIELD,QUERY_PARAM_ONE_FIELD,QUERY_PARAM_TWO_FIELD,STRING_HEADER_MEMBER_FIELD,NESTED_QUERY_PARAMETER_OPERATION_FIELD,REQUIRED_LIST_QUERY_PARAMS_FIELD,OPTIONAL_LIST_QUERY_PARAMS_FIELD,STATUS_CODE_ON_INPUT_FIELD)); + + private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); + + private final String pathParam; + + private final String queryParamOne; + + private final String queryParamTwo; + + private final String stringHeaderMember; + + private final NestedQueryParameterOperation nestedQueryParameterOperation; + + private final List requiredListQueryParams; + + private final List optionalListQueryParams; + + private final Integer statusCodeOnInput; + + private QueryParameterOperationRequest(BuilderImpl builder) { + super(builder); + this.pathParam = builder.pathParam; + this.queryParamOne = builder.queryParamOne; + this.queryParamTwo = builder.queryParamTwo; + this.stringHeaderMember = builder.stringHeaderMember; + this.nestedQueryParameterOperation = builder.nestedQueryParameterOperation; + this.requiredListQueryParams = builder.requiredListQueryParams; + this.optionalListQueryParams = builder.optionalListQueryParams; + this.statusCodeOnInput = builder.statusCodeOnInput; + } + + /** + * Returns the value of the PathParam property for this object. + * @return The value of the PathParam property for this object. + */ + public final String pathParam() { + return pathParam; + } + + /** + * Returns the value of the QueryParamOne property for this object. + * @return The value of the QueryParamOne property for this object. + */ + public final String queryParamOne() { + return queryParamOne; + } + + /** + * Returns the value of the QueryParamTwo property for this object. + * @return The value of the QueryParamTwo property for this object. + */ + public final String queryParamTwo() { + return queryParamTwo; + } + + /** + * Returns the value of the StringHeaderMember property for this object. + * @return The value of the StringHeaderMember property for this object. + */ + public final String stringHeaderMember() { + return stringHeaderMember; + } + + /** + * Returns the value of the NestedQueryParameterOperation property for this object. + * @return The value of the NestedQueryParameterOperation property for this object. + */ + public final NestedQueryParameterOperation nestedQueryParameterOperation() { + return nestedQueryParameterOperation; + } + + /** + * For responses, this returns true if the service returned a value for the RequiredListQueryParams property. This DOES NOT check that the value is non-empty (for which, you should check the {@code isEmpty()} method on the property). This is useful because the SDK will never return a null collection or map, but you may need to differentiate between the service returning nothing (or null) and the service returning an empty collection or map. For requests, this returns true if a value for the property was specified in the request builder, and false if a value was not specified. + */ + public final boolean hasRequiredListQueryParams() { + return requiredListQueryParams != null && !(requiredListQueryParams instanceof SdkAutoConstructList); + } + + /** + * Returns the value of the RequiredListQueryParams property for this object. + *

+ * Attempts to modify the collection returned by this method will result in an UnsupportedOperationException. + *

+ *

+ * This method will never return null. If you would like to know whether the service returned this field (so that you can differentiate between null and empty), you can use the {@link #hasRequiredListQueryParams} method. + *

+ * @return The value of the RequiredListQueryParams property for this object. + */ + public final List requiredListQueryParams() { + return requiredListQueryParams; + } + + /** + * For responses, this returns true if the service returned a value for the OptionalListQueryParams property. This DOES NOT check that the value is non-empty (for which, you should check the {@code isEmpty()} method on the property). This is useful because the SDK will never return a null collection or map, but you may need to differentiate between the service returning nothing (or null) and the service returning an empty collection or map. For requests, this returns true if a value for the property was specified in the request builder, and false if a value was not specified. + */ + public final boolean hasOptionalListQueryParams() { + return optionalListQueryParams != null && !(optionalListQueryParams instanceof SdkAutoConstructList); + } + + /** + * Returns the value of the OptionalListQueryParams property for this object. + *

+ * Attempts to modify the collection returned by this method will result in an UnsupportedOperationException. + *

+ *

+ * This method will never return null. If you would like to know whether the service returned this field (so that you can differentiate between null and empty), you can use the {@link #hasOptionalListQueryParams} method. + *

+ * @return The value of the OptionalListQueryParams property for this object. + */ + public final List optionalListQueryParams() { + return optionalListQueryParams; + } + + /** + * Returns the value of the StatusCodeOnInput property for this object. + * @return The value of the StatusCodeOnInput property for this object. + */ + public final Integer statusCodeOnInput() { + return statusCodeOnInput; + } + + @Override + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static Class serializableBuilderClass() { + return BuilderImpl.class; + } + + @Override + public final int hashCode() { + int hashCode = 1; + hashCode = 31 * hashCode + super.hashCode(); + hashCode = 31 * hashCode + Objects.hashCode(pathParam()); + hashCode = 31 * hashCode + Objects.hashCode(queryParamOne()); + hashCode = 31 * hashCode + Objects.hashCode(queryParamTwo()); + hashCode = 31 * hashCode + Objects.hashCode(stringHeaderMember()); + hashCode = 31 * hashCode + Objects.hashCode(nestedQueryParameterOperation()); + hashCode = 31 * hashCode + Objects.hashCode(hasRequiredListQueryParams() ? requiredListQueryParams() : null); + hashCode = 31 * hashCode + Objects.hashCode(hasOptionalListQueryParams() ? optionalListQueryParams() : null); + hashCode = 31 * hashCode + Objects.hashCode(statusCodeOnInput()); + return hashCode; + } + + @Override + public final boolean equals(Object obj) { + return super.equals(obj) && equalsBySdkFields(obj); + } + + @Override + public final boolean equalsBySdkFields(Object obj) { + if (this == obj) { + return true; } + if (obj == null) { + return false; + } + if (!(obj instanceof QueryParameterOperationRequest)) { + return false; + } + QueryParameterOperationRequest other = (QueryParameterOperationRequest) obj; + return Objects.equals(pathParam(), other.pathParam())&&Objects.equals(queryParamOne(), other.queryParamOne())&&Objects.equals(queryParamTwo(), other.queryParamTwo())&&Objects.equals(stringHeaderMember(), other.stringHeaderMember())&&Objects.equals(nestedQueryParameterOperation(), other.nestedQueryParameterOperation())&&hasRequiredListQueryParams() == other.hasRequiredListQueryParams() && Objects.equals(requiredListQueryParams(), other.requiredListQueryParams())&&hasOptionalListQueryParams() == other.hasOptionalListQueryParams() && Objects.equals(optionalListQueryParams(), other.optionalListQueryParams())&&Objects.equals(statusCodeOnInput(), other.statusCodeOnInput()); + } + + /** + * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be redacted from this string using a placeholder value. + */ + @Override + public final String toString() { + return ToString.builder("QueryParameterOperationRequest").add("PathParam", pathParam()).add("QueryParamOne", queryParamOne()).add("QueryParamTwo", queryParamTwo()).add("StringHeaderMember", stringHeaderMember()).add("NestedQueryParameterOperation", nestedQueryParameterOperation()).add("RequiredListQueryParams", hasRequiredListQueryParams() ? requiredListQueryParams() : null).add("OptionalListQueryParams", hasOptionalListQueryParams() ? optionalListQueryParams() : null).add("StatusCodeOnInput", statusCodeOnInput()).build(); + } + + public final Optional getValueForField(String fieldName, Class clazz) { + switch (fieldName) { + case "PathParam":return Optional.ofNullable(clazz.cast(pathParam())); + case "QueryParamOne":return Optional.ofNullable(clazz.cast(queryParamOne())); + case "QueryParamTwo":return Optional.ofNullable(clazz.cast(queryParamTwo())); + case "StringHeaderMember":return Optional.ofNullable(clazz.cast(stringHeaderMember())); + case "NestedQueryParameterOperation":return Optional.ofNullable(clazz.cast(nestedQueryParameterOperation())); + case "RequiredListQueryParams":return Optional.ofNullable(clazz.cast(requiredListQueryParams())); + case "OptionalListQueryParams":return Optional.ofNullable(clazz.cast(optionalListQueryParams())); + case "StatusCodeOnInput":return Optional.ofNullable(clazz.cast(statusCodeOnInput())); + default:return Optional.empty(); + } + } + + @Override + public final List> sdkFields() { + return SDK_FIELDS; + } + + @Override + public final Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; + } + + private static Map> memberNameToFieldInitializer() { + Map> map = new HashMap<>(); + map.put("PathParam", PATH_PARAM_FIELD); + map.put("QueryParamOne", QUERY_PARAM_ONE_FIELD); + map.put("QueryParamTwo", QUERY_PARAM_TWO_FIELD); + map.put("x-amz-header-string", STRING_HEADER_MEMBER_FIELD); + map.put("NestedQueryParameterOperation", NESTED_QUERY_PARAMETER_OPERATION_FIELD); + map.put("RequiredListQueryParams", REQUIRED_LIST_QUERY_PARAMS_FIELD); + map.put("OptionalListQueryParams", OPTIONAL_LIST_QUERY_PARAMS_FIELD); + map.put("StatusCodeOnInput", STATUS_CODE_ON_INPUT_FIELD); + return Collections.unmodifiableMap(map); + } + + private static Function getter(Function g) { + return obj -> g.apply((QueryParameterOperationRequest) obj); + } + + private static BiConsumer setter(BiConsumer s) { + return (obj, val) -> s.accept((Builder) obj, val); + } + + @Mutable + @NotThreadSafe + public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, CopyableBuilder { + /** + * Sets the value of the PathParam property for this object. + * + * @param pathParam The new value for the PathParam property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder pathParam(String pathParam); /** - * Returns the value of the PathParam property for this object. + * Sets the value of the QueryParamOne property for this object. * - * @return The value of the PathParam property for this object. + * @param queryParamOne The new value for the QueryParamOne property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String pathParam() { - return pathParam; - } + Builder queryParamOne(String queryParamOne); /** - * Returns the value of the QueryParamOne property for this object. + * Sets the value of the QueryParamTwo property for this object. * - * @return The value of the QueryParamOne property for this object. + * @param queryParamTwo The new value for the QueryParamTwo property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String queryParamOne() { - return queryParamOne; - } + Builder queryParamTwo(String queryParamTwo); /** - * Returns the value of the QueryParamTwo property for this object. + * Sets the value of the StringHeaderMember property for this object. * - * @return The value of the QueryParamTwo property for this object. + * @param stringHeaderMember The new value for the StringHeaderMember property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String queryParamTwo() { - return queryParamTwo; - } + Builder stringHeaderMember(String stringHeaderMember); /** - * Returns the value of the StringHeaderMember property for this object. + * Sets the value of the NestedQueryParameterOperation property for this object. * - * @return The value of the StringHeaderMember property for this object. + * @param nestedQueryParameterOperation The new value for the NestedQueryParameterOperation property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final String stringHeaderMember() { - return stringHeaderMember; - } + Builder nestedQueryParameterOperation( + NestedQueryParameterOperation nestedQueryParameterOperation); /** - * Returns the value of the NestedQueryParameterOperation property for this object. + * Sets the value of the NestedQueryParameterOperation property for this object. + * + * This is a convenience method that creates an instance of the {@link NestedQueryParameterOperation.Builder} avoiding the need to create one manually via {@link NestedQueryParameterOperation#builder()}. * - * @return The value of the NestedQueryParameterOperation property for this object. + *

When the {@link Consumer} completes, {@link NestedQueryParameterOperation.Builder#build()} is called immediately and its result is passed to {@link #nestedQueryParameterOperation(NestedQueryParameterOperation)}. + * @param nestedQueryParameterOperation a consumer that will call methods on {@link NestedQueryParameterOperation.Builder} + * @return Returns a reference to this object so that method calls can be chained together. + * @see #nestedQueryParameterOperation(NestedQueryParameterOperation) */ - public final NestedQueryParameterOperation nestedQueryParameterOperation() { - return nestedQueryParameterOperation; + default Builder nestedQueryParameterOperation( + Consumer nestedQueryParameterOperation) { + return nestedQueryParameterOperation(NestedQueryParameterOperation.builder().applyMutation(nestedQueryParameterOperation).build()); } /** - * For responses, this returns true if the service returned a value for the RequiredListQueryParams property. This - * DOES NOT check that the value is non-empty (for which, you should check the {@code isEmpty()} method on the - * property). This is useful because the SDK will never return a null collection or map, but you may need to - * differentiate between the service returning nothing (or null) and the service returning an empty collection or - * map. For requests, this returns true if a value for the property was specified in the request builder, and false - * if a value was not specified. + * Sets the value of the RequiredListQueryParams property for this object. + * + * @param requiredListQueryParams The new value for the RequiredListQueryParams property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final boolean hasRequiredListQueryParams() { - return requiredListQueryParams != null && !(requiredListQueryParams instanceof SdkAutoConstructList); - } + Builder requiredListQueryParams(Collection requiredListQueryParams); /** - * Returns the value of the RequiredListQueryParams property for this object. - *

- * Attempts to modify the collection returned by this method will result in an UnsupportedOperationException. - *

- *

- * This method will never return null. If you would like to know whether the service returned this field (so that - * you can differentiate between null and empty), you can use the {@link #hasRequiredListQueryParams} method. - *

+ * Sets the value of the RequiredListQueryParams property for this object. * - * @return The value of the RequiredListQueryParams property for this object. + * @param requiredListQueryParams The new value for the RequiredListQueryParams property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final List requiredListQueryParams() { - return requiredListQueryParams; - } + Builder requiredListQueryParams(Integer... requiredListQueryParams); /** - * For responses, this returns true if the service returned a value for the OptionalListQueryParams property. This - * DOES NOT check that the value is non-empty (for which, you should check the {@code isEmpty()} method on the - * property). This is useful because the SDK will never return a null collection or map, but you may need to - * differentiate between the service returning nothing (or null) and the service returning an empty collection or - * map. For requests, this returns true if a value for the property was specified in the request builder, and false - * if a value was not specified. + * Sets the value of the OptionalListQueryParams property for this object. + * + * @param optionalListQueryParams The new value for the OptionalListQueryParams property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final boolean hasOptionalListQueryParams() { - return optionalListQueryParams != null && !(optionalListQueryParams instanceof SdkAutoConstructList); - } + Builder optionalListQueryParams(Collection optionalListQueryParams); /** - * Returns the value of the OptionalListQueryParams property for this object. - *

- * Attempts to modify the collection returned by this method will result in an UnsupportedOperationException. - *

- *

- * This method will never return null. If you would like to know whether the service returned this field (so that - * you can differentiate between null and empty), you can use the {@link #hasOptionalListQueryParams} method. - *

+ * Sets the value of the OptionalListQueryParams property for this object. * - * @return The value of the OptionalListQueryParams property for this object. + * @param optionalListQueryParams The new value for the OptionalListQueryParams property for this object. + * @return Returns a reference to this object so that method calls can be chained together. */ - public final List optionalListQueryParams() { - return optionalListQueryParams; + Builder optionalListQueryParams(Integer... optionalListQueryParams); + + /** + * Sets the value of the StatusCodeOnInput property for this object. + * + * @param statusCodeOnInput The new value for the StatusCodeOnInput property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder statusCodeOnInput(Integer statusCodeOnInput); + + @Override + Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration); + + @Override + Builder overrideConfiguration( + Consumer builderConsumer); + } + + static final class BuilderImpl extends JsonProtocolTestsRequest.BuilderImpl implements Builder { + private String pathParam; + + private String queryParamOne; + + private String queryParamTwo; + + private String stringHeaderMember; + + private NestedQueryParameterOperation nestedQueryParameterOperation; + + private List requiredListQueryParams = DefaultSdkAutoConstructList.getInstance(); + + private List optionalListQueryParams = DefaultSdkAutoConstructList.getInstance(); + + private Integer statusCodeOnInput; + + private BuilderImpl() { + } + + private BuilderImpl(QueryParameterOperationRequest model) { + super(model);pathParam(model.pathParam); + queryParamOne(model.queryParamOne); + queryParamTwo(model.queryParamTwo); + stringHeaderMember(model.stringHeaderMember); + nestedQueryParameterOperation(model.nestedQueryParameterOperation); + requiredListQueryParams(model.requiredListQueryParams); + optionalListQueryParams(model.optionalListQueryParams); + statusCodeOnInput(model.statusCodeOnInput); + } + + public final String getPathParam() { + return pathParam; + } + + public final void setPathParam(String pathParam) { + this.pathParam = pathParam; } @Override - public Builder toBuilder() { - return new BuilderImpl(this); + public final Builder pathParam(String pathParam) { + this.pathParam = pathParam; + return this; } - public static Builder builder() { - return new BuilderImpl(); + public final String getQueryParamOne() { + return queryParamOne; } - public static Class serializableBuilderClass() { - return BuilderImpl.class; + public final void setQueryParamOne(String queryParamOne) { + this.queryParamOne = queryParamOne; } @Override - public final int hashCode() { - int hashCode = 1; - hashCode = 31 * hashCode + super.hashCode(); - hashCode = 31 * hashCode + Objects.hashCode(pathParam()); - hashCode = 31 * hashCode + Objects.hashCode(queryParamOne()); - hashCode = 31 * hashCode + Objects.hashCode(queryParamTwo()); - hashCode = 31 * hashCode + Objects.hashCode(stringHeaderMember()); - hashCode = 31 * hashCode + Objects.hashCode(nestedQueryParameterOperation()); - hashCode = 31 * hashCode + Objects.hashCode(hasRequiredListQueryParams() ? requiredListQueryParams() : null); - hashCode = 31 * hashCode + Objects.hashCode(hasOptionalListQueryParams() ? optionalListQueryParams() : null); - return hashCode; + public final Builder queryParamOne(String queryParamOne) { + this.queryParamOne = queryParamOne; + return this; + } + + public final String getQueryParamTwo() { + return queryParamTwo; + } + + public final void setQueryParamTwo(String queryParamTwo) { + this.queryParamTwo = queryParamTwo; } @Override - public final boolean equals(Object obj) { - return super.equals(obj) && equalsBySdkFields(obj); + public final Builder queryParamTwo(String queryParamTwo) { + this.queryParamTwo = queryParamTwo; + return this; + } + + public final String getStringHeaderMember() { + return stringHeaderMember; + } + + public final void setStringHeaderMember(String stringHeaderMember) { + this.stringHeaderMember = stringHeaderMember; } @Override - public final boolean equalsBySdkFields(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof QueryParameterOperationRequest)) { - return false; - } - QueryParameterOperationRequest other = (QueryParameterOperationRequest) obj; - return Objects.equals(pathParam(), other.pathParam()) && Objects.equals(queryParamOne(), other.queryParamOne()) - && Objects.equals(queryParamTwo(), other.queryParamTwo()) - && Objects.equals(stringHeaderMember(), other.stringHeaderMember()) - && Objects.equals(nestedQueryParameterOperation(), other.nestedQueryParameterOperation()) - && hasRequiredListQueryParams() == other.hasRequiredListQueryParams() - && Objects.equals(requiredListQueryParams(), other.requiredListQueryParams()) - && hasOptionalListQueryParams() == other.hasOptionalListQueryParams() - && Objects.equals(optionalListQueryParams(), other.optionalListQueryParams()); + public final Builder stringHeaderMember(String stringHeaderMember) { + this.stringHeaderMember = stringHeaderMember; + return this; + } + + public final NestedQueryParameterOperation.Builder getNestedQueryParameterOperation() { + return nestedQueryParameterOperation != null ? nestedQueryParameterOperation.toBuilder() : null; + } + + public final void setNestedQueryParameterOperation( + NestedQueryParameterOperation.BuilderImpl nestedQueryParameterOperation) { + this.nestedQueryParameterOperation = nestedQueryParameterOperation != null ? nestedQueryParameterOperation.build() : null; + } + + @Override + public final Builder nestedQueryParameterOperation( + NestedQueryParameterOperation nestedQueryParameterOperation) { + this.nestedQueryParameterOperation = nestedQueryParameterOperation; + return this; + } + + public final Collection getRequiredListQueryParams() { + if (requiredListQueryParams instanceof SdkAutoConstructList) {return null;}return requiredListQueryParams; + } + + public final void setRequiredListQueryParams(Collection requiredListQueryParams) { + this.requiredListQueryParams = ListOfIntegersCopier.copy(requiredListQueryParams); + } + + @Override + public final Builder requiredListQueryParams(Collection requiredListQueryParams) { + this.requiredListQueryParams = ListOfIntegersCopier.copy(requiredListQueryParams); + return this; + } + + @Override + @SafeVarargs + public final Builder requiredListQueryParams(Integer... requiredListQueryParams) { + requiredListQueryParams(Arrays.asList(requiredListQueryParams));return this; + } + + public final Collection getOptionalListQueryParams() { + if (optionalListQueryParams instanceof SdkAutoConstructList) {return null;}return optionalListQueryParams; + } + + public final void setOptionalListQueryParams(Collection optionalListQueryParams) { + this.optionalListQueryParams = ListOfIntegersCopier.copy(optionalListQueryParams); + } + + @Override + public final Builder optionalListQueryParams(Collection optionalListQueryParams) { + this.optionalListQueryParams = ListOfIntegersCopier.copy(optionalListQueryParams); + return this; + } + + @Override + @SafeVarargs + public final Builder optionalListQueryParams(Integer... optionalListQueryParams) { + optionalListQueryParams(Arrays.asList(optionalListQueryParams));return this; + } + + public final Integer getStatusCodeOnInput() { + return statusCodeOnInput; + } + + public final void setStatusCodeOnInput(Integer statusCodeOnInput) { + this.statusCodeOnInput = statusCodeOnInput; + } + + @Override + public final Builder statusCodeOnInput(Integer statusCodeOnInput) { + this.statusCodeOnInput = statusCodeOnInput; + return this; + } + + @Override + public Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration) { + super.overrideConfiguration(overrideConfiguration); + return this; + } + + @Override + public Builder overrideConfiguration( + Consumer builderConsumer) { + super.overrideConfiguration(builderConsumer); + return this; } - /** - * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be - * redacted from this string using a placeholder value. - */ @Override - public final String toString() { - return ToString.builder("QueryParameterOperationRequest").add("PathParam", pathParam()) - .add("QueryParamOne", queryParamOne()).add("QueryParamTwo", queryParamTwo()) - .add("StringHeaderMember", stringHeaderMember()) - .add("NestedQueryParameterOperation", nestedQueryParameterOperation()) - .add("RequiredListQueryParams", hasRequiredListQueryParams() ? requiredListQueryParams() : null) - .add("OptionalListQueryParams", hasOptionalListQueryParams() ? optionalListQueryParams() : null).build(); - } - - public final Optional getValueForField(String fieldName, Class clazz) { - switch (fieldName) { - case "PathParam": - return Optional.ofNullable(clazz.cast(pathParam())); - case "QueryParamOne": - return Optional.ofNullable(clazz.cast(queryParamOne())); - case "QueryParamTwo": - return Optional.ofNullable(clazz.cast(queryParamTwo())); - case "StringHeaderMember": - return Optional.ofNullable(clazz.cast(stringHeaderMember())); - case "NestedQueryParameterOperation": - return Optional.ofNullable(clazz.cast(nestedQueryParameterOperation())); - case "RequiredListQueryParams": - return Optional.ofNullable(clazz.cast(requiredListQueryParams())); - case "OptionalListQueryParams": - return Optional.ofNullable(clazz.cast(optionalListQueryParams())); - default: - return Optional.empty(); - } + public QueryParameterOperationRequest build() { + return new QueryParameterOperationRequest(this); } @Override - public final List> sdkFields() { - return SDK_FIELDS; + public List> sdkFields() { + return SDK_FIELDS; } @Override - public final Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; - } - - private static Map> memberNameToFieldInitializer() { - Map> map = new HashMap<>(); - map.put("PathParam", PATH_PARAM_FIELD); - map.put("QueryParamOne", QUERY_PARAM_ONE_FIELD); - map.put("QueryParamTwo", QUERY_PARAM_TWO_FIELD); - map.put("x-amz-header-string", STRING_HEADER_MEMBER_FIELD); - map.put("NestedQueryParameterOperation", NESTED_QUERY_PARAMETER_OPERATION_FIELD); - map.put("RequiredListQueryParams", REQUIRED_LIST_QUERY_PARAMS_FIELD); - map.put("OptionalListQueryParams", OPTIONAL_LIST_QUERY_PARAMS_FIELD); - return Collections.unmodifiableMap(map); - } - - private static Function getter(Function g) { - return obj -> g.apply((QueryParameterOperationRequest) obj); - } - - private static BiConsumer setter(BiConsumer s) { - return (obj, val) -> s.accept((Builder) obj, val); - } - - @Mutable - @NotThreadSafe - public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, - CopyableBuilder { - /** - * Sets the value of the PathParam property for this object. - * - * @param pathParam - * The new value for the PathParam property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder pathParam(String pathParam); - - /** - * Sets the value of the QueryParamOne property for this object. - * - * @param queryParamOne - * The new value for the QueryParamOne property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder queryParamOne(String queryParamOne); - - /** - * Sets the value of the QueryParamTwo property for this object. - * - * @param queryParamTwo - * The new value for the QueryParamTwo property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder queryParamTwo(String queryParamTwo); - - /** - * Sets the value of the StringHeaderMember property for this object. - * - * @param stringHeaderMember - * The new value for the StringHeaderMember property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder stringHeaderMember(String stringHeaderMember); - - /** - * Sets the value of the NestedQueryParameterOperation property for this object. - * - * @param nestedQueryParameterOperation - * The new value for the NestedQueryParameterOperation property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder nestedQueryParameterOperation(NestedQueryParameterOperation nestedQueryParameterOperation); - - /** - * Sets the value of the NestedQueryParameterOperation property for this object. - * - * This is a convenience method that creates an instance of the {@link NestedQueryParameterOperation.Builder} - * avoiding the need to create one manually via {@link NestedQueryParameterOperation#builder()}. - * - *

- * When the {@link Consumer} completes, {@link NestedQueryParameterOperation.Builder#build()} is called - * immediately and its result is passed to {@link #nestedQueryParameterOperation(NestedQueryParameterOperation)}. - * - * @param nestedQueryParameterOperation - * a consumer that will call methods on {@link NestedQueryParameterOperation.Builder} - * @return Returns a reference to this object so that method calls can be chained together. - * @see #nestedQueryParameterOperation(NestedQueryParameterOperation) - */ - default Builder nestedQueryParameterOperation( - Consumer nestedQueryParameterOperation) { - return nestedQueryParameterOperation(NestedQueryParameterOperation.builder() - .applyMutation(nestedQueryParameterOperation).build()); - } - - /** - * Sets the value of the RequiredListQueryParams property for this object. - * - * @param requiredListQueryParams - * The new value for the RequiredListQueryParams property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder requiredListQueryParams(Collection requiredListQueryParams); - - /** - * Sets the value of the RequiredListQueryParams property for this object. - * - * @param requiredListQueryParams - * The new value for the RequiredListQueryParams property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder requiredListQueryParams(Integer... requiredListQueryParams); - - /** - * Sets the value of the OptionalListQueryParams property for this object. - * - * @param optionalListQueryParams - * The new value for the OptionalListQueryParams property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder optionalListQueryParams(Collection optionalListQueryParams); - - /** - * Sets the value of the OptionalListQueryParams property for this object. - * - * @param optionalListQueryParams - * The new value for the OptionalListQueryParams property for this object. - * @return Returns a reference to this object so that method calls can be chained together. - */ - Builder optionalListQueryParams(Integer... optionalListQueryParams); - - @Override - Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration); - - @Override - Builder overrideConfiguration(Consumer builderConsumer); - } - - static final class BuilderImpl extends JsonProtocolTestsRequest.BuilderImpl implements Builder { - private String pathParam; - - private String queryParamOne; - - private String queryParamTwo; - - private String stringHeaderMember; - - private NestedQueryParameterOperation nestedQueryParameterOperation; - - private List requiredListQueryParams = DefaultSdkAutoConstructList.getInstance(); - - private List optionalListQueryParams = DefaultSdkAutoConstructList.getInstance(); - - private BuilderImpl() { - } - - private BuilderImpl(QueryParameterOperationRequest model) { - super(model); - pathParam(model.pathParam); - queryParamOne(model.queryParamOne); - queryParamTwo(model.queryParamTwo); - stringHeaderMember(model.stringHeaderMember); - nestedQueryParameterOperation(model.nestedQueryParameterOperation); - requiredListQueryParams(model.requiredListQueryParams); - optionalListQueryParams(model.optionalListQueryParams); - } - - public final String getPathParam() { - return pathParam; - } - - public final void setPathParam(String pathParam) { - this.pathParam = pathParam; - } - - @Override - public final Builder pathParam(String pathParam) { - this.pathParam = pathParam; - return this; - } - - public final String getQueryParamOne() { - return queryParamOne; - } - - public final void setQueryParamOne(String queryParamOne) { - this.queryParamOne = queryParamOne; - } - - @Override - public final Builder queryParamOne(String queryParamOne) { - this.queryParamOne = queryParamOne; - return this; - } - - public final String getQueryParamTwo() { - return queryParamTwo; - } - - public final void setQueryParamTwo(String queryParamTwo) { - this.queryParamTwo = queryParamTwo; - } - - @Override - public final Builder queryParamTwo(String queryParamTwo) { - this.queryParamTwo = queryParamTwo; - return this; - } - - public final String getStringHeaderMember() { - return stringHeaderMember; - } - - public final void setStringHeaderMember(String stringHeaderMember) { - this.stringHeaderMember = stringHeaderMember; - } - - @Override - public final Builder stringHeaderMember(String stringHeaderMember) { - this.stringHeaderMember = stringHeaderMember; - return this; - } - - public final NestedQueryParameterOperation.Builder getNestedQueryParameterOperation() { - return nestedQueryParameterOperation != null ? nestedQueryParameterOperation.toBuilder() : null; - } - - public final void setNestedQueryParameterOperation(NestedQueryParameterOperation.BuilderImpl nestedQueryParameterOperation) { - this.nestedQueryParameterOperation = nestedQueryParameterOperation != null ? nestedQueryParameterOperation.build() - : null; - } - - @Override - public final Builder nestedQueryParameterOperation(NestedQueryParameterOperation nestedQueryParameterOperation) { - this.nestedQueryParameterOperation = nestedQueryParameterOperation; - return this; - } - - public final Collection getRequiredListQueryParams() { - if (requiredListQueryParams instanceof SdkAutoConstructList) { - return null; - } - return requiredListQueryParams; - } - - public final void setRequiredListQueryParams(Collection requiredListQueryParams) { - this.requiredListQueryParams = ListOfIntegersCopier.copy(requiredListQueryParams); - } - - @Override - public final Builder requiredListQueryParams(Collection requiredListQueryParams) { - this.requiredListQueryParams = ListOfIntegersCopier.copy(requiredListQueryParams); - return this; - } - - @Override - @SafeVarargs - public final Builder requiredListQueryParams(Integer... requiredListQueryParams) { - requiredListQueryParams(Arrays.asList(requiredListQueryParams)); - return this; - } - - public final Collection getOptionalListQueryParams() { - if (optionalListQueryParams instanceof SdkAutoConstructList) { - return null; - } - return optionalListQueryParams; - } - - public final void setOptionalListQueryParams(Collection optionalListQueryParams) { - this.optionalListQueryParams = ListOfIntegersCopier.copy(optionalListQueryParams); - } - - @Override - public final Builder optionalListQueryParams(Collection optionalListQueryParams) { - this.optionalListQueryParams = ListOfIntegersCopier.copy(optionalListQueryParams); - return this; - } - - @Override - @SafeVarargs - public final Builder optionalListQueryParams(Integer... optionalListQueryParams) { - optionalListQueryParams(Arrays.asList(optionalListQueryParams)); - return this; - } - - @Override - public Builder overrideConfiguration(AwsRequestOverrideConfiguration overrideConfiguration) { - super.overrideConfiguration(overrideConfiguration); - return this; - } - - @Override - public Builder overrideConfiguration(Consumer builderConsumer) { - super.overrideConfiguration(builderConsumer); - return this; - } - - @Override - public QueryParameterOperationRequest build() { - return new QueryParameterOperationRequest(this); - } - - @Override - public List> sdkFields() { - return SDK_FIELDS; - } - - @Override - public Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; - } + public Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; } + } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationresponse.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationresponse.java index 14376b1d1c97..e87e085e71de 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationresponse.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/queryparameteroperationresponse.java @@ -1,122 +1,331 @@ package software.amazon.awssdk.services.jsonprotocoltests.model; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.Mutable; import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.SdkPojo; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.LocationTrait; import software.amazon.awssdk.utils.ToString; import software.amazon.awssdk.utils.builder.CopyableBuilder; import software.amazon.awssdk.utils.builder.ToCopyableBuilder; +/** + */ @Generated("software.amazon.awssdk:codegen") -public final class QueryParameterOperationResponse extends JsonProtocolTestsResponse implements - ToCopyableBuilder { - private static final List> SDK_FIELDS = Collections.emptyList(); +public final class QueryParameterOperationResponse extends JsonProtocolTestsResponse implements ToCopyableBuilder { + private static final SdkField RESPONSE_HEADER_MEMBER_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("ResponseHeaderMember") + .getter(getter(QueryParameterOperationResponse::responseHeaderMember)) + .setter(setter(Builder::responseHeaderMember)) + .traits(LocationTrait.builder() + .location(MarshallLocation.HEADER) + .locationName("x-amz-response-header") + .build()).build(); - private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); + private static final SdkField RESPONSE_STATUS_CODE_FIELD = SdkField.builder(MarshallingType.INTEGER) + .memberName("ResponseStatusCode") + .getter(getter(QueryParameterOperationResponse::responseStatusCode)) + .setter(setter(Builder::responseStatusCode)) + .traits(LocationTrait.builder() + .location(MarshallLocation.STATUS_CODE) + .locationName("ResponseStatusCode") + .build()).build(); - private QueryParameterOperationResponse(BuilderImpl builder) { - super(builder); + private static final SdkField URI_MEMBER_ON_OUTPUT_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("UriMemberOnOutput") + .getter(getter(QueryParameterOperationResponse::uriMemberOnOutput)) + .setter(setter(Builder::uriMemberOnOutput)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("UriMemberOnOutput") + .build()).build(); + + private static final SdkField QUERY_MEMBER_ON_OUTPUT_FIELD = SdkField.builder(MarshallingType.STRING) + .memberName("QueryMemberOnOutput") + .getter(getter(QueryParameterOperationResponse::queryMemberOnOutput)) + .setter(setter(Builder::queryMemberOnOutput)) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("QueryMemberOnOutput") + .build()).build(); + + private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(RESPONSE_HEADER_MEMBER_FIELD,RESPONSE_STATUS_CODE_FIELD,URI_MEMBER_ON_OUTPUT_FIELD,QUERY_MEMBER_ON_OUTPUT_FIELD)); + + private static final Map> SDK_NAME_TO_FIELD = memberNameToFieldInitializer(); + + private final String responseHeaderMember; + + private final Integer responseStatusCode; + + private final String uriMemberOnOutput; + + private final String queryMemberOnOutput; + + private QueryParameterOperationResponse(BuilderImpl builder) { + super(builder); + this.responseHeaderMember = builder.responseHeaderMember; + this.responseStatusCode = builder.responseStatusCode; + this.uriMemberOnOutput = builder.uriMemberOnOutput; + this.queryMemberOnOutput = builder.queryMemberOnOutput; + } + + /** + * Returns the value of the ResponseHeaderMember property for this object. + * @return The value of the ResponseHeaderMember property for this object. + */ + public final String responseHeaderMember() { + return responseHeaderMember; + } + + /** + * Returns the value of the ResponseStatusCode property for this object. + * @return The value of the ResponseStatusCode property for this object. + */ + public final Integer responseStatusCode() { + return responseStatusCode; + } + + /** + * Returns the value of the UriMemberOnOutput property for this object. + * @return The value of the UriMemberOnOutput property for this object. + */ + public final String uriMemberOnOutput() { + return uriMemberOnOutput; + } + + /** + * Returns the value of the QueryMemberOnOutput property for this object. + * @return The value of the QueryMemberOnOutput property for this object. + */ + public final String queryMemberOnOutput() { + return queryMemberOnOutput; + } + + @Override + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static Class serializableBuilderClass() { + return BuilderImpl.class; + } + + @Override + public final int hashCode() { + int hashCode = 1; + hashCode = 31 * hashCode + super.hashCode(); + hashCode = 31 * hashCode + Objects.hashCode(responseHeaderMember()); + hashCode = 31 * hashCode + Objects.hashCode(responseStatusCode()); + hashCode = 31 * hashCode + Objects.hashCode(uriMemberOnOutput()); + hashCode = 31 * hashCode + Objects.hashCode(queryMemberOnOutput()); + return hashCode; + } + + @Override + public final boolean equals(Object obj) { + return super.equals(obj) && equalsBySdkFields(obj); + } + + @Override + public final boolean equalsBySdkFields(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; } + if (!(obj instanceof QueryParameterOperationResponse)) { + return false; + } + QueryParameterOperationResponse other = (QueryParameterOperationResponse) obj; + return Objects.equals(responseHeaderMember(), other.responseHeaderMember())&&Objects.equals(responseStatusCode(), other.responseStatusCode())&&Objects.equals(uriMemberOnOutput(), other.uriMemberOnOutput())&&Objects.equals(queryMemberOnOutput(), other.queryMemberOnOutput()); + } - @Override - public Builder toBuilder() { - return new BuilderImpl(this); + /** + * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be redacted from this string using a placeholder value. + */ + @Override + public final String toString() { + return ToString.builder("QueryParameterOperationResponse").add("ResponseHeaderMember", responseHeaderMember()).add("ResponseStatusCode", responseStatusCode()).add("UriMemberOnOutput", uriMemberOnOutput()).add("QueryMemberOnOutput", queryMemberOnOutput()).build(); + } + + public final Optional getValueForField(String fieldName, Class clazz) { + switch (fieldName) { + case "ResponseHeaderMember":return Optional.ofNullable(clazz.cast(responseHeaderMember())); + case "ResponseStatusCode":return Optional.ofNullable(clazz.cast(responseStatusCode())); + case "UriMemberOnOutput":return Optional.ofNullable(clazz.cast(uriMemberOnOutput())); + case "QueryMemberOnOutput":return Optional.ofNullable(clazz.cast(queryMemberOnOutput())); + default:return Optional.empty(); + } + } + + @Override + public final List> sdkFields() { + return SDK_FIELDS; + } + + @Override + public final Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; + } + + private static Map> memberNameToFieldInitializer() { + Map> map = new HashMap<>(); + map.put("x-amz-response-header", RESPONSE_HEADER_MEMBER_FIELD); + map.put("ResponseStatusCode", RESPONSE_STATUS_CODE_FIELD); + map.put("UriMemberOnOutput", URI_MEMBER_ON_OUTPUT_FIELD); + map.put("QueryMemberOnOutput", QUERY_MEMBER_ON_OUTPUT_FIELD); + return Collections.unmodifiableMap(map); + } + + private static Function getter(Function g) { + return obj -> g.apply((QueryParameterOperationResponse) obj); + } + + private static BiConsumer setter(BiConsumer s) { + return (obj, val) -> s.accept((Builder) obj, val); + } + + @Mutable + @NotThreadSafe + public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, CopyableBuilder { + /** + * Sets the value of the ResponseHeaderMember property for this object. + * + * @param responseHeaderMember The new value for the ResponseHeaderMember property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder responseHeaderMember(String responseHeaderMember); + + /** + * Sets the value of the ResponseStatusCode property for this object. + * + * @param responseStatusCode The new value for the ResponseStatusCode property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder responseStatusCode(Integer responseStatusCode); + + /** + * Sets the value of the UriMemberOnOutput property for this object. + * + * @param uriMemberOnOutput The new value for the UriMemberOnOutput property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder uriMemberOnOutput(String uriMemberOnOutput); + + /** + * Sets the value of the QueryMemberOnOutput property for this object. + * + * @param queryMemberOnOutput The new value for the QueryMemberOnOutput property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder queryMemberOnOutput(String queryMemberOnOutput); + } + + static final class BuilderImpl extends JsonProtocolTestsResponse.BuilderImpl implements Builder { + private String responseHeaderMember; + + private Integer responseStatusCode; + + private String uriMemberOnOutput; + + private String queryMemberOnOutput; + + private BuilderImpl() { } - public static Builder builder() { - return new BuilderImpl(); + private BuilderImpl(QueryParameterOperationResponse model) { + super(model);responseHeaderMember(model.responseHeaderMember); + responseStatusCode(model.responseStatusCode); + uriMemberOnOutput(model.uriMemberOnOutput); + queryMemberOnOutput(model.queryMemberOnOutput); } - public static Class serializableBuilderClass() { - return BuilderImpl.class; + public final String getResponseHeaderMember() { + return responseHeaderMember; } - @Override - public final int hashCode() { - int hashCode = 1; - hashCode = 31 * hashCode + super.hashCode(); - return hashCode; + public final void setResponseHeaderMember(String responseHeaderMember) { + this.responseHeaderMember = responseHeaderMember; } @Override - public final boolean equals(Object obj) { - return super.equals(obj) && equalsBySdkFields(obj); + public final Builder responseHeaderMember(String responseHeaderMember) { + this.responseHeaderMember = responseHeaderMember; + return this; } - @Override - public final boolean equalsBySdkFields(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof QueryParameterOperationResponse)) { - return false; - } - return true; + public final Integer getResponseStatusCode() { + return responseStatusCode; + } + + public final void setResponseStatusCode(Integer responseStatusCode) { + this.responseStatusCode = responseStatusCode; } - /** - * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be - * redacted from this string using a placeholder value. - */ @Override - public final String toString() { - return ToString.builder("QueryParameterOperationResponse").build(); + public final Builder responseStatusCode(Integer responseStatusCode) { + this.responseStatusCode = responseStatusCode; + return this; } - public final Optional getValueForField(String fieldName, Class clazz) { - return Optional.empty(); + public final String getUriMemberOnOutput() { + return uriMemberOnOutput; } - @Override - public final List> sdkFields() { - return SDK_FIELDS; + public final void setUriMemberOnOutput(String uriMemberOnOutput) { + this.uriMemberOnOutput = uriMemberOnOutput; } @Override - public final Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; + public final Builder uriMemberOnOutput(String uriMemberOnOutput) { + this.uriMemberOnOutput = uriMemberOnOutput; + return this; } - private static Map> memberNameToFieldInitializer() { - return Collections.emptyMap(); + public final String getQueryMemberOnOutput() { + return queryMemberOnOutput; } - @Mutable - @NotThreadSafe - public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, - CopyableBuilder { + public final void setQueryMemberOnOutput(String queryMemberOnOutput) { + this.queryMemberOnOutput = queryMemberOnOutput; } - static final class BuilderImpl extends JsonProtocolTestsResponse.BuilderImpl implements Builder { - private BuilderImpl() { - } - - private BuilderImpl(QueryParameterOperationResponse model) { - super(model); - } + @Override + public final Builder queryMemberOnOutput(String queryMemberOnOutput) { + this.queryMemberOnOutput = queryMemberOnOutput; + return this; + } - @Override - public QueryParameterOperationResponse build() { - return new QueryParameterOperationResponse(this); - } + @Override + public QueryParameterOperationResponse build() { + return new QueryParameterOperationResponse(this); + } - @Override - public List> sdkFields() { - return SDK_FIELDS; - } + @Override + public List> sdkFields() { + return SDK_FIELDS; + } - @Override - public Map> sdkFieldNameToField() { - return SDK_NAME_TO_FIELD; - } + @Override + public Map> sdkFieldNameToField() { + return SDK_NAME_TO_FIELD; } + } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/service-2.json index 5b2f1c8ebcaf..88a71b8f470f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/service-2.json +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/service-2.json @@ -127,7 +127,8 @@ "method":"DELETE", "requestUri":"/2016-03-11/queryParameterOperation/{PathParam}" }, - "input":{"shape":"QueryParameterOperationRequest"} + "input":{"shape":"QueryParameterOperationRequest"}, + "output":{"shape":"QueryParameterOperationResponse"} }, "OperationWithReservedKeywordMember": { "name": "DeprecatedRename", @@ -640,6 +641,15 @@ "shape":"String", "location":"querystring", "locationName":"QueryParamTwo" + }, + "NestedHeaderMember":{ + "shape":"String", + "location":"header", + "locationName":"x-amz-nested-header" + }, + "NestedStatusCode":{ + "shape":"Integer", + "location":"statusCode" } } }, @@ -682,10 +692,38 @@ "OptionalListQueryParams":{ "shape":"ListOfIntegers", "location":"querystring" + }, + "StatusCodeOnInput":{ + "shape":"Integer", + "location":"statusCode" } }, "payload":"NestedQueryParameterOperation" }, + "QueryParameterOperationResponse":{ + "type":"structure", + "members":{ + "ResponseHeaderMember":{ + "shape":"String", + "location":"header", + "locationName":"x-amz-response-header" + }, + "ResponseStatusCode":{ + "shape":"Integer", + "location":"statusCode" + }, + "UriMemberOnOutput":{ + "shape":"String", + "location":"uri", + "locationName":"UriMemberOnOutput" + }, + "QueryMemberOnOutput":{ + "shape":"String", + "location":"querystring", + "locationName":"QueryMemberOnOutput" + } + } + }, "ContainsReservedKeyword": { "type": "structure", "members": {