From c646b3be0c320d51b5dcab0ff44bc26c7d6ff9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Tue, 30 Jul 2024 13:22:43 -0700 Subject: [PATCH 01/14] Add RPCv2 module --- bom/pom.xml | 5 + codegen/pom.xml | 5 + core/protocols/pom.xml | 1 + core/protocols/smithy-rpcv2-protocol/pom.xml | 102 +++++++++++++++++++ test/protocol-tests/pom.xml | 5 + test/tests-coverage-reporting/pom.xml | 5 + 6 files changed, 123 insertions(+) create mode 100644 core/protocols/smithy-rpcv2-protocol/pom.xml diff --git a/bom/pom.xml b/bom/pom.xml index 072a36dc65a4..a50fcbc44b31 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -112,6 +112,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/codegen/pom.xml b/codegen/pom.xml index ad5c0ef76aaa..2d82ef7ce7ee 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -142,6 +142,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/core/protocols/pom.xml b/core/protocols/pom.xml index 73dd7f150875..f2284e1d6fb3 100644 --- a/core/protocols/pom.xml +++ b/core/protocols/pom.xml @@ -35,6 +35,7 @@ aws-json-protocol aws-cbor-protocol aws-xml-protocol + smithy-rpcv2-protocol protocol-core diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml new file mode 100644 index 000000000000..23e6bea4ca53 --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -0,0 +1,102 @@ + + + + + + protocols + software.amazon.awssdk + 2.26.27-SNAPSHOT + + 4.0.0 + + smithy-rpcv2-protocol + AWS Java SDK :: Core :: Protocols :: Smithy RPCv2 Protocol + The AWS SDK for Java - module holds the classes for Smithy RPCv2 Protocol + + https://aws.amazon.com/sdkforjava + + + + software.amazon.awssdk + aws-json-protocol + ${awsjavasdk.version} + + + software.amazon.awssdk + sdk-core + ${awsjavasdk.version} + + + software.amazon.awssdk + annotations + ${awsjavasdk.version} + + + software.amazon.awssdk + third-party-jackson-dataformat-cbor + ${awsjavasdk.version} + + + software.amazon.awssdk + third-party-jackson-core + ${awsjavasdk.version} + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.hamcrest + hamcrest-all + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + software.amazon.awssdk.protocols.rpcv2 + + + + + + + + diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index 0602a42e074b..177e3533b0e5 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -57,6 +57,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/test/tests-coverage-reporting/pom.xml b/test/tests-coverage-reporting/pom.xml index e2a433343dcc..1d38b6ecc0e3 100644 --- a/test/tests-coverage-reporting/pom.xml +++ b/test/tests-coverage-reporting/pom.xml @@ -142,6 +142,11 @@ software.amazon.awssdk ${awsjavasdk.version} + + smithy-rpcv2-protocol + software.amazon.awssdk + ${awsjavasdk.version} + netty-nio-client software.amazon.awssdk From 3a44186e5f3cc52cc2aa79e0b5d0a39c478aba02 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Wed, 31 Jul 2024 14:58:10 -0700 Subject: [PATCH 02/14] Add RPCv2 module (#5445) --- bom/pom.xml | 5 + codegen/pom.xml | 5 + core/protocols/pom.xml | 1 + core/protocols/smithy-rpcv2-protocol/pom.xml | 102 +++++++++++++++++++ test/protocol-tests/pom.xml | 5 + test/tests-coverage-reporting/pom.xml | 5 + 6 files changed, 123 insertions(+) create mode 100644 core/protocols/smithy-rpcv2-protocol/pom.xml diff --git a/bom/pom.xml b/bom/pom.xml index 072a36dc65a4..a50fcbc44b31 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -112,6 +112,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/codegen/pom.xml b/codegen/pom.xml index ad5c0ef76aaa..2d82ef7ce7ee 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -142,6 +142,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/core/protocols/pom.xml b/core/protocols/pom.xml index 73dd7f150875..f2284e1d6fb3 100644 --- a/core/protocols/pom.xml +++ b/core/protocols/pom.xml @@ -35,6 +35,7 @@ aws-json-protocol aws-cbor-protocol aws-xml-protocol + smithy-rpcv2-protocol protocol-core diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml new file mode 100644 index 000000000000..23e6bea4ca53 --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -0,0 +1,102 @@ + + + + + + protocols + software.amazon.awssdk + 2.26.27-SNAPSHOT + + 4.0.0 + + smithy-rpcv2-protocol + AWS Java SDK :: Core :: Protocols :: Smithy RPCv2 Protocol + The AWS SDK for Java - module holds the classes for Smithy RPCv2 Protocol + + https://aws.amazon.com/sdkforjava + + + + software.amazon.awssdk + aws-json-protocol + ${awsjavasdk.version} + + + software.amazon.awssdk + sdk-core + ${awsjavasdk.version} + + + software.amazon.awssdk + annotations + ${awsjavasdk.version} + + + software.amazon.awssdk + third-party-jackson-dataformat-cbor + ${awsjavasdk.version} + + + software.amazon.awssdk + third-party-jackson-core + ${awsjavasdk.version} + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.hamcrest + hamcrest-all + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + software.amazon.awssdk.protocols.rpcv2 + + + + + + + + diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index 0602a42e074b..177e3533b0e5 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -57,6 +57,11 @@ aws-xml-protocol ${awsjavasdk.version} + + software.amazon.awssdk + smithy-rpcv2-protocol + ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/test/tests-coverage-reporting/pom.xml b/test/tests-coverage-reporting/pom.xml index e2a433343dcc..1d38b6ecc0e3 100644 --- a/test/tests-coverage-reporting/pom.xml +++ b/test/tests-coverage-reporting/pom.xml @@ -142,6 +142,11 @@ software.amazon.awssdk ${awsjavasdk.version} + + smithy-rpcv2-protocol + software.amazon.awssdk + ${awsjavasdk.version} + netty-nio-client software.amazon.awssdk From 1a7a32fb66186078c1e37cfd5d5647add921457a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Tue, 6 Aug 2024 09:15:52 -0700 Subject: [PATCH 03/14] Comment out empty rpcv2 dependency --- codegen/pom.xml | 2 ++ core/protocols/smithy-rpcv2-protocol/pom.xml | 2 ++ test/protocol-tests/pom.xml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/codegen/pom.xml b/codegen/pom.xml index 2d82ef7ce7ee..a47e1eb3e55d 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -142,11 +142,13 @@ aws-xml-protocol ${awsjavasdk.version} + software.amazon.awssdk protocol-core diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml index 23e6bea4ca53..333dfe504fa3 100644 --- a/core/protocols/smithy-rpcv2-protocol/pom.xml +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -31,6 +31,7 @@ https://aws.amazon.com/sdkforjava + diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index 177e3533b0e5..b87ef01b8d42 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -57,11 +57,13 @@ aws-xml-protocol ${awsjavasdk.version} + software.amazon.awssdk protocol-core From ec554546ece723c84aee84e008d7b63b8bebe532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Tue, 6 Aug 2024 09:19:20 -0700 Subject: [PATCH 04/14] Sync version to 2.26.31-SNAPSHOT --- core/protocols/smithy-rpcv2-protocol/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml index 333dfe504fa3..8dde8b80902c 100644 --- a/core/protocols/smithy-rpcv2-protocol/pom.xml +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -20,7 +20,7 @@ protocols software.amazon.awssdk - 2.26.27-SNAPSHOT + 2.26.31-SNAPSHOT 4.0.0 From 0c89041120ced074f7583bcd3255b8d00459bbfd Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Wed, 7 Aug 2024 16:15:40 -0700 Subject: [PATCH 05/14] Sugmanue/add byte support (#5477) * Add support to serialize byte values * Add tests for byte support * Address PR comments --- .../awssdk/codegen/internal/TypeUtils.java | 1 + .../codegen/poet/model/alltypesrequest.java | 1143 +++++++++-------- .../codegen/poet/model/alltypesresponse.java | 1143 +++++++++-------- .../awssdk/codegen/poet/model/service-2.json | 3 + .../protocols/json/SdkJsonGenerator.java | 10 + .../json/StructuredJsonGenerator.java | 4 + .../internal/marshall/HeaderMarshaller.java | 2 + .../marshall/JsonProtocolMarshaller.java | 4 + .../marshall/QueryParamMarshaller.java | 2 + .../marshall/SimpleTypeJsonMarshaller.java | 7 + .../marshall/SimpleTypePathMarshaller.java | 3 + .../unmarshall/JsonProtocolUnmarshaller.java | 1 + .../core/StringToValueConverter.java | 2 + .../core/ValueToStringConverter.java | 2 + .../awssdk/core/protocol/MarshallingType.java | 2 + .../protocol/reflect/ShapeModelReflector.java | 4 +- .../suites/cases/json-core-input.json | 5 +- .../suites/cases/json-core-output.json | 5 +- .../codegen-resources/awsjson/service-2.json | 2 + .../codegen-resources/restjson/service-2.json | 2 + 20 files changed, 1246 insertions(+), 1101 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/TypeUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/TypeUtils.java index dadfee753a3b..8941bdd27da7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/TypeUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/TypeUtils.java @@ -85,6 +85,7 @@ public static final class TypeKey { MARSHALLING_TYPE_MAPPINGS.put("BigDecimal", "BIG_DECIMAL"); MARSHALLING_TYPE_MAPPINGS.put("InputStream", "STREAM"); MARSHALLING_TYPE_MAPPINGS.put("Short", "SHORT"); + MARSHALLING_TYPE_MAPPINGS.put("Byte", "BYTE"); MARSHALLING_TYPE_MAPPINGS.put(null, "NULL"); MARSHALLING_TYPE_MAPPINGS.put("Document", "DOCUMENT"); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesrequest.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesrequest.java index d2ecca7be480..72788016688a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesrequest.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesrequest.java @@ -37,414 +37,418 @@ */ @Generated("software.amazon.awssdk:codegen") public final class AllTypesRequest extends JsonProtocolTestsRequest implements - ToCopyableBuilder { + ToCopyableBuilder { private static final SdkField STRING_MEMBER_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("StringMember").getter(getter(AllTypesRequest::stringMember)).setter(setter(Builder::stringMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StringMember").build()).build(); + .memberName("StringMember").getter(getter(AllTypesRequest::stringMember)).setter(setter(Builder::stringMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StringMember").build()).build(); private static final SdkField INTEGER_MEMBER_FIELD = SdkField. builder(MarshallingType.INTEGER) - .memberName("IntegerMember").getter(getter(AllTypesRequest::integerMember)).setter(setter(Builder::integerMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("IntegerMember").build()).build(); + .memberName("IntegerMember").getter(getter(AllTypesRequest::integerMember)).setter(setter(Builder::integerMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("IntegerMember").build()).build(); private static final SdkField BOOLEAN_MEMBER_FIELD = SdkField. builder(MarshallingType.BOOLEAN) - .memberName("BooleanMember").getter(getter(AllTypesRequest::booleanMember)).setter(setter(Builder::booleanMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BooleanMember").build()).build(); + .memberName("BooleanMember").getter(getter(AllTypesRequest::booleanMember)).setter(setter(Builder::booleanMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BooleanMember").build()).build(); private static final SdkField FLOAT_MEMBER_FIELD = SdkField. builder(MarshallingType.FLOAT) - .memberName("FloatMember").getter(getter(AllTypesRequest::floatMember)).setter(setter(Builder::floatMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("FloatMember").build()).build(); + .memberName("FloatMember").getter(getter(AllTypesRequest::floatMember)).setter(setter(Builder::floatMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("FloatMember").build()).build(); private static final SdkField DOUBLE_MEMBER_FIELD = SdkField. builder(MarshallingType.DOUBLE) - .memberName("DoubleMember").getter(getter(AllTypesRequest::doubleMember)).setter(setter(Builder::doubleMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("DoubleMember").build()).build(); + .memberName("DoubleMember").getter(getter(AllTypesRequest::doubleMember)).setter(setter(Builder::doubleMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("DoubleMember").build()).build(); private static final SdkField LONG_MEMBER_FIELD = SdkField. builder(MarshallingType.LONG) - .memberName("LongMember").getter(getter(AllTypesRequest::longMember)).setter(setter(Builder::longMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("LongMember").build()).build(); + .memberName("LongMember").getter(getter(AllTypesRequest::longMember)).setter(setter(Builder::longMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("LongMember").build()).build(); private static final SdkField SHORT_MEMBER_FIELD = SdkField. builder(MarshallingType.SHORT) - .memberName("ShortMember").getter(getter(AllTypesRequest::shortMember)).setter(setter(Builder::shortMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ShortMember").build()).build(); + .memberName("ShortMember").getter(getter(AllTypesRequest::shortMember)).setter(setter(Builder::shortMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ShortMember").build()).build(); + + private static final SdkField BYTE_MEMBER_FIELD = SdkField. builder(MarshallingType.BYTE) + .memberName("ByteMember").getter(getter(AllTypesRequest::byteMember)).setter(setter(Builder::byteMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ByteMember").build()).build(); private static final SdkField> SIMPLE_LIST_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("SimpleList") - .getter(getter(AllTypesRequest::simpleList)) - .setter(setter(Builder::simpleList)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("SimpleList").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("SimpleList") + .getter(getter(AllTypesRequest::simpleList)) + .setter(setter(Builder::simpleList)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("SimpleList").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField> LIST_OF_ENUMS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfEnums") - .getter(getter(AllTypesRequest::listOfEnumsAsStrings)) - .setter(setter(Builder::listOfEnumsWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfEnums").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfEnums") + .getter(getter(AllTypesRequest::listOfEnumsAsStrings)) + .setter(setter(Builder::listOfEnumsWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfEnums").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAPS_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMaps") - .getter(getter(AllTypesRequest::listOfMaps)) - .setter(setter(Builder::listOfMaps)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMaps").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMaps") + .getter(getter(AllTypesRequest::listOfMaps)) + .setter(setter(Builder::listOfMaps)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMaps").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField> LIST_OF_STRUCTS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfStructs") - .getter(getter(AllTypesRequest::listOfStructs)) - .setter(setter(Builder::listOfStructs)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfStructs").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfStructs") + .getter(getter(AllTypesRequest::listOfStructs)) + .setter(setter(Builder::listOfStructs)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfStructs").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMapOfEnumToString") - .getter(getter(AllTypesRequest::listOfMapOfEnumToStringAsStrings)) - .setter(setter(Builder::listOfMapOfEnumToStringWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfEnumToString").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMapOfEnumToString") + .getter(getter(AllTypesRequest::listOfMapOfEnumToStringAsStrings)) + .setter(setter(Builder::listOfMapOfEnumToStringWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfEnumToString").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMapOfStringToStruct") - .getter(getter(AllTypesRequest::listOfMapOfStringToStruct)) - .setter(setter(Builder::listOfMapOfStringToStruct)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfStringToStruct").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMapOfStringToStruct") + .getter(getter(AllTypesRequest::listOfMapOfStringToStruct)) + .setter(setter(Builder::listOfMapOfStringToStruct)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfStringToStruct").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> MAP_OF_STRING_TO_INTEGER_LIST_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfStringToIntegerList") - .getter(getter(AllTypesRequest::mapOfStringToIntegerList)) - .setter(setter(Builder::mapOfStringToIntegerList)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToIntegerList").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.LIST) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.INTEGER) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfStringToIntegerList") + .getter(getter(AllTypesRequest::mapOfStringToIntegerList)) + .setter(setter(Builder::mapOfStringToIntegerList)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToIntegerList").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.LIST) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.INTEGER) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()) + .build()).build()).build()).build(); private static final SdkField> MAP_OF_STRING_TO_STRING_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToString") - .getter(getter(AllTypesRequest::mapOfStringToString)) - .setter(setter(Builder::mapOfStringToString)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToString").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToString") + .getter(getter(AllTypesRequest::mapOfStringToString)) + .setter(setter(Builder::mapOfStringToString)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToString").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 SdkField> MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToSimpleStruct") - .getter(getter(AllTypesRequest::mapOfStringToSimpleStruct)) - .setter(setter(Builder::mapOfStringToSimpleStruct)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToSimpleStruct").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToSimpleStruct") + .getter(getter(AllTypesRequest::mapOfStringToSimpleStruct)) + .setter(setter(Builder::mapOfStringToSimpleStruct)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToSimpleStruct").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField> MAP_OF_ENUM_TO_ENUM_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToEnum") - .getter(getter(AllTypesRequest::mapOfEnumToEnumAsStrings)) - .setter(setter(Builder::mapOfEnumToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToEnum").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToEnum") + .getter(getter(AllTypesRequest::mapOfEnumToEnumAsStrings)) + .setter(setter(Builder::mapOfEnumToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToEnum").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 SdkField> MAP_OF_ENUM_TO_STRING_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToString") - .getter(getter(AllTypesRequest::mapOfEnumToStringAsStrings)) - .setter(setter(Builder::mapOfEnumToStringWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToString").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToString") + .getter(getter(AllTypesRequest::mapOfEnumToStringAsStrings)) + .setter(setter(Builder::mapOfEnumToStringWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToString").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 SdkField> MAP_OF_STRING_TO_ENUM_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToEnum") - .getter(getter(AllTypesRequest::mapOfStringToEnumAsStrings)) - .setter(setter(Builder::mapOfStringToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToEnum").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToEnum") + .getter(getter(AllTypesRequest::mapOfStringToEnumAsStrings)) + .setter(setter(Builder::mapOfStringToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToEnum").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 SdkField> MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToSimpleStruct") - .getter(getter(AllTypesRequest::mapOfEnumToSimpleStructAsStrings)) - .setter(setter(Builder::mapOfEnumToSimpleStructWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToSimpleStruct").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToSimpleStruct") + .getter(getter(AllTypesRequest::mapOfEnumToSimpleStructAsStrings)) + .setter(setter(Builder::mapOfEnumToSimpleStructWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToSimpleStruct").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField>> MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfEnumToListOfEnums") - .getter(getter(AllTypesRequest::mapOfEnumToListOfEnumsAsStrings)) - .setter(setter(Builder::mapOfEnumToListOfEnumsWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToListOfEnums").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.LIST) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfEnumToListOfEnums") + .getter(getter(AllTypesRequest::mapOfEnumToListOfEnumsAsStrings)) + .setter(setter(Builder::mapOfEnumToListOfEnumsWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToListOfEnums").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.LIST) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfEnumToMapOfStringToEnum") - .getter(getter(AllTypesRequest::mapOfEnumToMapOfStringToEnumAsStrings)) - .setter(setter(Builder::mapOfEnumToMapOfStringToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToMapOfStringToEnum") - .build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfEnumToMapOfStringToEnum") + .getter(getter(AllTypesRequest::mapOfEnumToMapOfStringToEnumAsStrings)) + .setter(setter(Builder::mapOfEnumToMapOfStringToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToMapOfStringToEnum") + .build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField TIMESTAMP_MEMBER_FIELD = SdkField. builder(MarshallingType.INSTANT) - .memberName("TimestampMember").getter(getter(AllTypesRequest::timestampMember)) - .setter(setter(Builder::timestampMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("TimestampMember").build()).build(); + .memberName("TimestampMember").getter(getter(AllTypesRequest::timestampMember)) + .setter(setter(Builder::timestampMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("TimestampMember").build()).build(); private static final SdkField STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("StructWithNestedTimestampMember") - .getter(getter(AllTypesRequest::structWithNestedTimestampMember)) - .setter(setter(Builder::structWithNestedTimestampMember)) - .constructor(StructWithTimestamp::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedTimestampMember") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("StructWithNestedTimestampMember") + .getter(getter(AllTypesRequest::structWithNestedTimestampMember)) + .setter(setter(Builder::structWithNestedTimestampMember)) + .constructor(StructWithTimestamp::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedTimestampMember") + .build()).build(); private static final SdkField BLOB_ARG_FIELD = SdkField. builder(MarshallingType.SDK_BYTES) - .memberName("BlobArg").getter(getter(AllTypesRequest::blobArg)).setter(setter(Builder::blobArg)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobArg").build()).build(); + .memberName("BlobArg").getter(getter(AllTypesRequest::blobArg)).setter(setter(Builder::blobArg)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobArg").build()).build(); private static final SdkField STRUCT_WITH_NESTED_BLOB_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("StructWithNestedBlob") - .getter(getter(AllTypesRequest::structWithNestedBlob)).setter(setter(Builder::structWithNestedBlob)) - .constructor(StructWithNestedBlobType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedBlob").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("StructWithNestedBlob") + .getter(getter(AllTypesRequest::structWithNestedBlob)).setter(setter(Builder::structWithNestedBlob)) + .constructor(StructWithNestedBlobType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedBlob").build()) + .build(); private static final SdkField> BLOB_MAP_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("BlobMap") - .getter(getter(AllTypesRequest::blobMap)) - .setter(setter(Builder::blobMap)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobMap").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_BYTES) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("BlobMap") + .getter(getter(AllTypesRequest::blobMap)) + .setter(setter(Builder::blobMap)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobMap").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_BYTES) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField> LIST_OF_BLOBS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfBlobs") - .getter(getter(AllTypesRequest::listOfBlobs)) - .setter(setter(Builder::listOfBlobs)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfBlobs").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.SDK_BYTES) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfBlobs") + .getter(getter(AllTypesRequest::listOfBlobs)) + .setter(setter(Builder::listOfBlobs)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfBlobs").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.SDK_BYTES) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField RECURSIVE_STRUCT_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("RecursiveStruct") - .getter(getter(AllTypesRequest::recursiveStruct)).setter(setter(Builder::recursiveStruct)) - .constructor(RecursiveStructType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("RecursiveStruct").build()).build(); + . builder(MarshallingType.SDK_POJO).memberName("RecursiveStruct") + .getter(getter(AllTypesRequest::recursiveStruct)).setter(setter(Builder::recursiveStruct)) + .constructor(RecursiveStructType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("RecursiveStruct").build()).build(); private static final SdkField POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("PolymorphicTypeWithSubTypes") - .getter(getter(AllTypesRequest::polymorphicTypeWithSubTypes)) - .setter(setter(Builder::polymorphicTypeWithSubTypes)) - .constructor(BaseType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithSubTypes") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("PolymorphicTypeWithSubTypes") + .getter(getter(AllTypesRequest::polymorphicTypeWithSubTypes)) + .setter(setter(Builder::polymorphicTypeWithSubTypes)) + .constructor(BaseType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithSubTypes") + .build()).build(); private static final SdkField POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("PolymorphicTypeWithoutSubTypes") - .getter(getter(AllTypesRequest::polymorphicTypeWithoutSubTypes)) - .setter(setter(Builder::polymorphicTypeWithoutSubTypes)) - .constructor(SubTypeOne::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithoutSubTypes") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("PolymorphicTypeWithoutSubTypes") + .getter(getter(AllTypesRequest::polymorphicTypeWithoutSubTypes)) + .setter(setter(Builder::polymorphicTypeWithoutSubTypes)) + .constructor(SubTypeOne::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithoutSubTypes") + .build()).build(); private static final SdkField ENUM_TYPE_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("EnumType").getter(getter(AllTypesRequest::enumTypeAsString)).setter(setter(Builder::enumType)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("EnumType").build()).build(); + .memberName("EnumType").getter(getter(AllTypesRequest::enumTypeAsString)).setter(setter(Builder::enumType)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("EnumType").build()).build(); private static final SdkField UNDERSCORE_NAME_TYPE_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("Underscore_Name_Type") - .getter(getter(AllTypesRequest::underscore_Name_Type)).setter(setter(Builder::underscore_Name_Type)) - .constructor(Underscore_Name_Type::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("Underscore_Name_Type").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("Underscore_Name_Type") + .getter(getter(AllTypesRequest::underscore_Name_Type)).setter(setter(Builder::underscore_Name_Type)) + .constructor(Underscore_Name_Type::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("Underscore_Name_Type").build()) + .build(); private static final SdkField MY_DOCUMENT_FIELD = SdkField. builder(MarshallingType.DOCUMENT) - .memberName("MyDocument").getter(getter(AllTypesRequest::myDocument)).setter(setter(Builder::myDocument)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MyDocument").build()).build(); + .memberName("MyDocument").getter(getter(AllTypesRequest::myDocument)).setter(setter(Builder::myDocument)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MyDocument").build()).build(); private static final SdkField ALL_TYPES_UNION_STRUCTURE_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("AllTypesUnionStructure") - .getter(getter(AllTypesRequest::allTypesUnionStructure)).setter(setter(Builder::allTypesUnionStructure)) - .constructor(AllTypesUnionStructure::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("AllTypesUnionStructure").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("AllTypesUnionStructure") + .getter(getter(AllTypesRequest::allTypesUnionStructure)).setter(setter(Builder::allTypesUnionStructure)) + .constructor(AllTypesUnionStructure::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("AllTypesUnionStructure").build()) + .build(); private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(STRING_MEMBER_FIELD, - INTEGER_MEMBER_FIELD, BOOLEAN_MEMBER_FIELD, FLOAT_MEMBER_FIELD, DOUBLE_MEMBER_FIELD, LONG_MEMBER_FIELD, - SHORT_MEMBER_FIELD, SIMPLE_LIST_FIELD, LIST_OF_ENUMS_FIELD, LIST_OF_MAPS_FIELD, LIST_OF_STRUCTS_FIELD, - LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD, LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD, MAP_OF_STRING_TO_INTEGER_LIST_FIELD, - MAP_OF_STRING_TO_STRING_FIELD, MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD, MAP_OF_ENUM_TO_ENUM_FIELD, - MAP_OF_ENUM_TO_STRING_FIELD, MAP_OF_STRING_TO_ENUM_FIELD, MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD, - MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD, MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD, TIMESTAMP_MEMBER_FIELD, - STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD, BLOB_ARG_FIELD, STRUCT_WITH_NESTED_BLOB_FIELD, BLOB_MAP_FIELD, - LIST_OF_BLOBS_FIELD, RECURSIVE_STRUCT_FIELD, POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD, - POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD, ENUM_TYPE_FIELD, UNDERSCORE_NAME_TYPE_FIELD, MY_DOCUMENT_FIELD, - ALL_TYPES_UNION_STRUCTURE_FIELD)); + INTEGER_MEMBER_FIELD, BOOLEAN_MEMBER_FIELD, FLOAT_MEMBER_FIELD, DOUBLE_MEMBER_FIELD, LONG_MEMBER_FIELD, + SHORT_MEMBER_FIELD, BYTE_MEMBER_FIELD, SIMPLE_LIST_FIELD, LIST_OF_ENUMS_FIELD, LIST_OF_MAPS_FIELD, + LIST_OF_STRUCTS_FIELD, LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD, LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD, + MAP_OF_STRING_TO_INTEGER_LIST_FIELD, MAP_OF_STRING_TO_STRING_FIELD, MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD, + MAP_OF_ENUM_TO_ENUM_FIELD, MAP_OF_ENUM_TO_STRING_FIELD, MAP_OF_STRING_TO_ENUM_FIELD, + MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD, MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD, MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD, + TIMESTAMP_MEMBER_FIELD, STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD, BLOB_ARG_FIELD, STRUCT_WITH_NESTED_BLOB_FIELD, + BLOB_MAP_FIELD, LIST_OF_BLOBS_FIELD, RECURSIVE_STRUCT_FIELD, POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD, + POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD, ENUM_TYPE_FIELD, UNDERSCORE_NAME_TYPE_FIELD, MY_DOCUMENT_FIELD, + ALL_TYPES_UNION_STRUCTURE_FIELD)); private final String stringMember; @@ -460,6 +464,8 @@ SdkField. builder(MarshallingType.SDK_BYTES) private final Short shortMember; + private final Byte byteMember; + private final List simpleList; private final List listOfEnums; @@ -525,6 +531,7 @@ private AllTypesRequest(BuilderImpl builder) { this.doubleMember = builder.doubleMember; this.longMember = builder.longMember; this.shortMember = builder.shortMember; + this.byteMember = builder.byteMember; this.simpleList = builder.simpleList; this.listOfEnums = builder.listOfEnums; this.listOfMaps = builder.listOfMaps; @@ -557,7 +564,7 @@ private AllTypesRequest(BuilderImpl builder) { /** * Returns the value of the StringMember property for this object. - * + * * @return The value of the StringMember property for this object. */ public final String stringMember() { @@ -566,7 +573,7 @@ public final String stringMember() { /** * Returns the value of the IntegerMember property for this object. - * + * * @return The value of the IntegerMember property for this object. */ public final Integer integerMember() { @@ -575,7 +582,7 @@ public final Integer integerMember() { /** * Returns the value of the BooleanMember property for this object. - * + * * @return The value of the BooleanMember property for this object. */ public final Boolean booleanMember() { @@ -584,7 +591,7 @@ public final Boolean booleanMember() { /** * Returns the value of the FloatMember property for this object. - * + * * @return The value of the FloatMember property for this object. */ public final Float floatMember() { @@ -593,7 +600,7 @@ public final Float floatMember() { /** * Returns the value of the DoubleMember property for this object. - * + * * @return The value of the DoubleMember property for this object. */ public final Double doubleMember() { @@ -602,7 +609,7 @@ public final Double doubleMember() { /** * Returns the value of the LongMember property for this object. - * + * * @return The value of the LongMember property for this object. */ public final Long longMember() { @@ -611,13 +618,22 @@ public final Long longMember() { /** * Returns the value of the ShortMember property for this object. - * + * * @return The value of the ShortMember property for this object. */ public final Short shortMember() { return shortMember; } + /** + * Returns the value of the ByteMember property for this object. + * + * @return The value of the ByteMember property for this object. + */ + public final Byte byteMember() { + return byteMember; + } + /** * For responses, this returns true if the service returned a value for the SimpleList 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 @@ -639,7 +655,7 @@ public final boolean hasSimpleList() { * 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 #hasSimpleList} method. *

- * + * * @return The value of the SimpleList property for this object. */ public final List simpleList() { @@ -655,7 +671,7 @@ public final List simpleList() { * 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 #hasListOfEnums} method. *

- * + * * @return The value of the ListOfEnums property for this object. */ public final List listOfEnums() { @@ -683,7 +699,7 @@ public final boolean hasListOfEnums() { * 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 #hasListOfEnums} method. *

- * + * * @return The value of the ListOfEnums property for this object. */ public final List listOfEnumsAsStrings() { @@ -711,7 +727,7 @@ public final boolean hasListOfMaps() { * 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 #hasListOfMaps} method. *

- * + * * @return The value of the ListOfMaps property for this object. */ public final List> listOfMaps() { @@ -739,7 +755,7 @@ public final boolean hasListOfStructs() { * 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 #hasListOfStructs} method. *

- * + * * @return The value of the ListOfStructs property for this object. */ public final List listOfStructs() { @@ -755,7 +771,7 @@ public final List listOfStructs() { * 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 #hasListOfMapOfEnumToString} method. *

- * + * * @return The value of the ListOfMapOfEnumToString property for this object. */ public final List> listOfMapOfEnumToString() { @@ -783,7 +799,7 @@ public final boolean hasListOfMapOfEnumToString() { * 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 #hasListOfMapOfEnumToString} method. *

- * + * * @return The value of the ListOfMapOfEnumToString property for this object. */ public final List> listOfMapOfEnumToStringAsStrings() { @@ -811,7 +827,7 @@ public final boolean hasListOfMapOfStringToStruct() { * 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 #hasListOfMapOfStringToStruct} method. *

- * + * * @return The value of the ListOfMapOfStringToStruct property for this object. */ public final List> listOfMapOfStringToStruct() { @@ -839,7 +855,7 @@ public final boolean hasMapOfStringToIntegerList() { * 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 #hasMapOfStringToIntegerList} method. *

- * + * * @return The value of the MapOfStringToIntegerList property for this object. */ public final Map> mapOfStringToIntegerList() { @@ -867,7 +883,7 @@ public final boolean hasMapOfStringToString() { * 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 #hasMapOfStringToString} method. *

- * + * * @return The value of the MapOfStringToString property for this object. */ public final Map mapOfStringToString() { @@ -895,7 +911,7 @@ public final boolean hasMapOfStringToSimpleStruct() { * 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 #hasMapOfStringToSimpleStruct} method. *

- * + * * @return The value of the MapOfStringToSimpleStruct property for this object. */ public final Map mapOfStringToSimpleStruct() { @@ -911,7 +927,7 @@ public final Map mapOfStringToSimpleStruct() { * 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 #hasMapOfEnumToEnum} method. *

- * + * * @return The value of the MapOfEnumToEnum property for this object. */ public final Map mapOfEnumToEnum() { @@ -939,7 +955,7 @@ public final boolean hasMapOfEnumToEnum() { * 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 #hasMapOfEnumToEnum} method. *

- * + * * @return The value of the MapOfEnumToEnum property for this object. */ public final Map mapOfEnumToEnumAsStrings() { @@ -955,7 +971,7 @@ public final Map mapOfEnumToEnumAsStrings() { * 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 #hasMapOfEnumToString} method. *

- * + * * @return The value of the MapOfEnumToString property for this object. */ public final Map mapOfEnumToString() { @@ -983,7 +999,7 @@ public final boolean hasMapOfEnumToString() { * 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 #hasMapOfEnumToString} method. *

- * + * * @return The value of the MapOfEnumToString property for this object. */ public final Map mapOfEnumToStringAsStrings() { @@ -999,7 +1015,7 @@ public final Map mapOfEnumToStringAsStrings() { * 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 #hasMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfStringToEnum property for this object. */ public final Map mapOfStringToEnum() { @@ -1027,7 +1043,7 @@ public final boolean hasMapOfStringToEnum() { * 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 #hasMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfStringToEnum property for this object. */ public final Map mapOfStringToEnumAsStrings() { @@ -1043,7 +1059,7 @@ public final Map mapOfStringToEnumAsStrings() { * 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 #hasMapOfEnumToSimpleStruct} method. *

- * + * * @return The value of the MapOfEnumToSimpleStruct property for this object. */ public final Map mapOfEnumToSimpleStruct() { @@ -1071,7 +1087,7 @@ public final boolean hasMapOfEnumToSimpleStruct() { * 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 #hasMapOfEnumToSimpleStruct} method. *

- * + * * @return The value of the MapOfEnumToSimpleStruct property for this object. */ public final Map mapOfEnumToSimpleStructAsStrings() { @@ -1087,7 +1103,7 @@ public final Map mapOfEnumToSimpleStructAsStrings() { * 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 #hasMapOfEnumToListOfEnums} method. *

- * + * * @return The value of the MapOfEnumToListOfEnums property for this object. */ public final Map> mapOfEnumToListOfEnums() { @@ -1115,7 +1131,7 @@ public final boolean hasMapOfEnumToListOfEnums() { * 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 #hasMapOfEnumToListOfEnums} method. *

- * + * * @return The value of the MapOfEnumToListOfEnums property for this object. */ public final Map> mapOfEnumToListOfEnumsAsStrings() { @@ -1131,7 +1147,7 @@ public final Map> mapOfEnumToListOfEnumsAsStrings() { * 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 #hasMapOfEnumToMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfEnumToMapOfStringToEnum property for this object. */ public final Map> mapOfEnumToMapOfStringToEnum() { @@ -1159,7 +1175,7 @@ public final boolean hasMapOfEnumToMapOfStringToEnum() { * 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 #hasMapOfEnumToMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfEnumToMapOfStringToEnum property for this object. */ public final Map> mapOfEnumToMapOfStringToEnumAsStrings() { @@ -1168,7 +1184,7 @@ public final Map> mapOfEnumToMapOfStringToEnumAsStri /** * Returns the value of the TimestampMember property for this object. - * + * * @return The value of the TimestampMember property for this object. */ public final Instant timestampMember() { @@ -1177,7 +1193,7 @@ public final Instant timestampMember() { /** * Returns the value of the StructWithNestedTimestampMember property for this object. - * + * * @return The value of the StructWithNestedTimestampMember property for this object. */ public final StructWithTimestamp structWithNestedTimestampMember() { @@ -1186,7 +1202,7 @@ public final StructWithTimestamp structWithNestedTimestampMember() { /** * Returns the value of the BlobArg property for this object. - * + * * @return The value of the BlobArg property for this object. */ public final SdkBytes blobArg() { @@ -1195,7 +1211,7 @@ public final SdkBytes blobArg() { /** * Returns the value of the StructWithNestedBlob property for this object. - * + * * @return The value of the StructWithNestedBlob property for this object. */ public final StructWithNestedBlobType structWithNestedBlob() { @@ -1223,7 +1239,7 @@ public final boolean hasBlobMap() { * 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 #hasBlobMap} method. *

- * + * * @return The value of the BlobMap property for this object. */ public final Map blobMap() { @@ -1251,7 +1267,7 @@ public final boolean hasListOfBlobs() { * 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 #hasListOfBlobs} method. *

- * + * * @return The value of the ListOfBlobs property for this object. */ public final List listOfBlobs() { @@ -1260,7 +1276,7 @@ public final List listOfBlobs() { /** * Returns the value of the RecursiveStruct property for this object. - * + * * @return The value of the RecursiveStruct property for this object. */ public final RecursiveStructType recursiveStruct() { @@ -1269,7 +1285,7 @@ public final RecursiveStructType recursiveStruct() { /** * Returns the value of the PolymorphicTypeWithSubTypes property for this object. - * + * * @return The value of the PolymorphicTypeWithSubTypes property for this object. */ public final BaseType polymorphicTypeWithSubTypes() { @@ -1278,7 +1294,7 @@ public final BaseType polymorphicTypeWithSubTypes() { /** * Returns the value of the PolymorphicTypeWithoutSubTypes property for this object. - * + * * @return The value of the PolymorphicTypeWithoutSubTypes property for this object. */ public final SubTypeOne polymorphicTypeWithoutSubTypes() { @@ -1292,7 +1308,7 @@ public final SubTypeOne polymorphicTypeWithoutSubTypes() { * return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from * {@link #enumTypeAsString}. *

- * + * * @return The value of the EnumType property for this object. * @see EnumType */ @@ -1307,7 +1323,7 @@ public final EnumType enumType() { * return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from * {@link #enumTypeAsString}. *

- * + * * @return The value of the EnumType property for this object. * @see EnumType */ @@ -1317,7 +1333,7 @@ public final String enumTypeAsString() { /** * Returns the value of the Underscore_Name_Type property for this object. - * + * * @return The value of the Underscore_Name_Type property for this object. */ public final Underscore_Name_Type underscore_Name_Type() { @@ -1326,7 +1342,7 @@ public final Underscore_Name_Type underscore_Name_Type() { /** * Returns the value of the MyDocument property for this object. - * + * * @return The value of the MyDocument property for this object. */ public final Document myDocument() { @@ -1335,7 +1351,7 @@ public final Document myDocument() { /** * Returns the value of the AllTypesUnionStructure property for this object. - * + * * @return The value of the AllTypesUnionStructure property for this object. */ public final AllTypesUnionStructure allTypesUnionStructure() { @@ -1366,6 +1382,7 @@ public final int hashCode() { hashCode = 31 * hashCode + Objects.hashCode(doubleMember()); hashCode = 31 * hashCode + Objects.hashCode(longMember()); hashCode = 31 * hashCode + Objects.hashCode(shortMember()); + hashCode = 31 * hashCode + Objects.hashCode(byteMember()); hashCode = 31 * hashCode + Objects.hashCode(hasSimpleList() ? simpleList() : null); hashCode = 31 * hashCode + Objects.hashCode(hasListOfEnums() ? listOfEnumsAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(hasListOfMaps() ? listOfMaps() : null); @@ -1381,7 +1398,7 @@ public final int hashCode() { hashCode = 31 * hashCode + Objects.hashCode(hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null); hashCode = 31 * hashCode - + Objects.hashCode(hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null); + + Objects.hashCode(hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(timestampMember()); hashCode = 31 * hashCode + Objects.hashCode(structWithNestedTimestampMember()); hashCode = 31 * hashCode + Objects.hashCode(blobArg()); @@ -1416,48 +1433,49 @@ public final boolean equalsBySdkFields(Object obj) { } AllTypesRequest other = (AllTypesRequest) obj; return Objects.equals(stringMember(), other.stringMember()) && Objects.equals(integerMember(), other.integerMember()) - && Objects.equals(booleanMember(), other.booleanMember()) && Objects.equals(floatMember(), other.floatMember()) - && Objects.equals(doubleMember(), other.doubleMember()) && Objects.equals(longMember(), other.longMember()) - && Objects.equals(shortMember(), other.shortMember()) && hasSimpleList() == other.hasSimpleList() - && Objects.equals(simpleList(), other.simpleList()) && hasListOfEnums() == other.hasListOfEnums() - && Objects.equals(listOfEnumsAsStrings(), other.listOfEnumsAsStrings()) - && hasListOfMaps() == other.hasListOfMaps() && Objects.equals(listOfMaps(), other.listOfMaps()) - && hasListOfStructs() == other.hasListOfStructs() && Objects.equals(listOfStructs(), other.listOfStructs()) - && hasListOfMapOfEnumToString() == other.hasListOfMapOfEnumToString() - && Objects.equals(listOfMapOfEnumToStringAsStrings(), other.listOfMapOfEnumToStringAsStrings()) - && hasListOfMapOfStringToStruct() == other.hasListOfMapOfStringToStruct() - && Objects.equals(listOfMapOfStringToStruct(), other.listOfMapOfStringToStruct()) - && hasMapOfStringToIntegerList() == other.hasMapOfStringToIntegerList() - && Objects.equals(mapOfStringToIntegerList(), other.mapOfStringToIntegerList()) - && hasMapOfStringToString() == other.hasMapOfStringToString() - && Objects.equals(mapOfStringToString(), other.mapOfStringToString()) - && hasMapOfStringToSimpleStruct() == other.hasMapOfStringToSimpleStruct() - && Objects.equals(mapOfStringToSimpleStruct(), other.mapOfStringToSimpleStruct()) - && hasMapOfEnumToEnum() == other.hasMapOfEnumToEnum() - && Objects.equals(mapOfEnumToEnumAsStrings(), other.mapOfEnumToEnumAsStrings()) - && hasMapOfEnumToString() == other.hasMapOfEnumToString() - && Objects.equals(mapOfEnumToStringAsStrings(), other.mapOfEnumToStringAsStrings()) - && hasMapOfStringToEnum() == other.hasMapOfStringToEnum() - && Objects.equals(mapOfStringToEnumAsStrings(), other.mapOfStringToEnumAsStrings()) - && hasMapOfEnumToSimpleStruct() == other.hasMapOfEnumToSimpleStruct() - && Objects.equals(mapOfEnumToSimpleStructAsStrings(), other.mapOfEnumToSimpleStructAsStrings()) - && hasMapOfEnumToListOfEnums() == other.hasMapOfEnumToListOfEnums() - && Objects.equals(mapOfEnumToListOfEnumsAsStrings(), other.mapOfEnumToListOfEnumsAsStrings()) - && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() - && Objects.equals(mapOfEnumToMapOfStringToEnumAsStrings(), other.mapOfEnumToMapOfStringToEnumAsStrings()) - && Objects.equals(timestampMember(), other.timestampMember()) - && Objects.equals(structWithNestedTimestampMember(), other.structWithNestedTimestampMember()) - && Objects.equals(blobArg(), other.blobArg()) - && Objects.equals(structWithNestedBlob(), other.structWithNestedBlob()) && hasBlobMap() == other.hasBlobMap() - && Objects.equals(blobMap(), other.blobMap()) && hasListOfBlobs() == other.hasListOfBlobs() - && Objects.equals(listOfBlobs(), other.listOfBlobs()) - && Objects.equals(recursiveStruct(), other.recursiveStruct()) - && Objects.equals(polymorphicTypeWithSubTypes(), other.polymorphicTypeWithSubTypes()) - && Objects.equals(polymorphicTypeWithoutSubTypes(), other.polymorphicTypeWithoutSubTypes()) - && Objects.equals(enumTypeAsString(), other.enumTypeAsString()) - && Objects.equals(underscore_Name_Type(), other.underscore_Name_Type()) - && Objects.equals(myDocument(), other.myDocument()) - && Objects.equals(allTypesUnionStructure(), other.allTypesUnionStructure()); + && Objects.equals(booleanMember(), other.booleanMember()) && Objects.equals(floatMember(), other.floatMember()) + && Objects.equals(doubleMember(), other.doubleMember()) && Objects.equals(longMember(), other.longMember()) + && Objects.equals(shortMember(), other.shortMember()) && Objects.equals(byteMember(), other.byteMember()) + && hasSimpleList() == other.hasSimpleList() && Objects.equals(simpleList(), other.simpleList()) + && hasListOfEnums() == other.hasListOfEnums() + && Objects.equals(listOfEnumsAsStrings(), other.listOfEnumsAsStrings()) + && hasListOfMaps() == other.hasListOfMaps() && Objects.equals(listOfMaps(), other.listOfMaps()) + && hasListOfStructs() == other.hasListOfStructs() && Objects.equals(listOfStructs(), other.listOfStructs()) + && hasListOfMapOfEnumToString() == other.hasListOfMapOfEnumToString() + && Objects.equals(listOfMapOfEnumToStringAsStrings(), other.listOfMapOfEnumToStringAsStrings()) + && hasListOfMapOfStringToStruct() == other.hasListOfMapOfStringToStruct() + && Objects.equals(listOfMapOfStringToStruct(), other.listOfMapOfStringToStruct()) + && hasMapOfStringToIntegerList() == other.hasMapOfStringToIntegerList() + && Objects.equals(mapOfStringToIntegerList(), other.mapOfStringToIntegerList()) + && hasMapOfStringToString() == other.hasMapOfStringToString() + && Objects.equals(mapOfStringToString(), other.mapOfStringToString()) + && hasMapOfStringToSimpleStruct() == other.hasMapOfStringToSimpleStruct() + && Objects.equals(mapOfStringToSimpleStruct(), other.mapOfStringToSimpleStruct()) + && hasMapOfEnumToEnum() == other.hasMapOfEnumToEnum() + && Objects.equals(mapOfEnumToEnumAsStrings(), other.mapOfEnumToEnumAsStrings()) + && hasMapOfEnumToString() == other.hasMapOfEnumToString() + && Objects.equals(mapOfEnumToStringAsStrings(), other.mapOfEnumToStringAsStrings()) + && hasMapOfStringToEnum() == other.hasMapOfStringToEnum() + && Objects.equals(mapOfStringToEnumAsStrings(), other.mapOfStringToEnumAsStrings()) + && hasMapOfEnumToSimpleStruct() == other.hasMapOfEnumToSimpleStruct() + && Objects.equals(mapOfEnumToSimpleStructAsStrings(), other.mapOfEnumToSimpleStructAsStrings()) + && hasMapOfEnumToListOfEnums() == other.hasMapOfEnumToListOfEnums() + && Objects.equals(mapOfEnumToListOfEnumsAsStrings(), other.mapOfEnumToListOfEnumsAsStrings()) + && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() + && Objects.equals(mapOfEnumToMapOfStringToEnumAsStrings(), other.mapOfEnumToMapOfStringToEnumAsStrings()) + && Objects.equals(timestampMember(), other.timestampMember()) + && Objects.equals(structWithNestedTimestampMember(), other.structWithNestedTimestampMember()) + && Objects.equals(blobArg(), other.blobArg()) + && Objects.equals(structWithNestedBlob(), other.structWithNestedBlob()) && hasBlobMap() == other.hasBlobMap() + && Objects.equals(blobMap(), other.blobMap()) && hasListOfBlobs() == other.hasListOfBlobs() + && Objects.equals(listOfBlobs(), other.listOfBlobs()) + && Objects.equals(recursiveStruct(), other.recursiveStruct()) + && Objects.equals(polymorphicTypeWithSubTypes(), other.polymorphicTypeWithSubTypes()) + && Objects.equals(polymorphicTypeWithoutSubTypes(), other.polymorphicTypeWithoutSubTypes()) + && Objects.equals(enumTypeAsString(), other.enumTypeAsString()) + && Objects.equals(underscore_Name_Type(), other.underscore_Name_Type()) + && Objects.equals(myDocument(), other.myDocument()) + && Objects.equals(allTypesUnionStructure(), other.allTypesUnionStructure()); } /** @@ -1467,114 +1485,117 @@ && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() @Override public final String toString() { return ToString - .builder("AllTypesRequest") - .add("StringMember", stringMember()) - .add("IntegerMember", integerMember()) - .add("BooleanMember", booleanMember()) - .add("FloatMember", floatMember()) - .add("DoubleMember", doubleMember()) - .add("LongMember", longMember()) - .add("ShortMember", shortMember()) - .add("SimpleList", hasSimpleList() ? simpleList() : null) - .add("ListOfEnums", hasListOfEnums() ? listOfEnumsAsStrings() : null) - .add("ListOfMaps", hasListOfMaps() ? listOfMaps() : null) - .add("ListOfStructs", hasListOfStructs() ? listOfStructs() : null) - .add("ListOfMapOfEnumToString", hasListOfMapOfEnumToString() ? listOfMapOfEnumToStringAsStrings() : null) - .add("ListOfMapOfStringToStruct", hasListOfMapOfStringToStruct() ? listOfMapOfStringToStruct() : null) - .add("MapOfStringToIntegerList", hasMapOfStringToIntegerList() ? mapOfStringToIntegerList() : null) - .add("MapOfStringToString", hasMapOfStringToString() ? mapOfStringToString() : null) - .add("MapOfStringToSimpleStruct", hasMapOfStringToSimpleStruct() ? mapOfStringToSimpleStruct() : null) - .add("MapOfEnumToEnum", hasMapOfEnumToEnum() ? mapOfEnumToEnumAsStrings() : null) - .add("MapOfEnumToString", hasMapOfEnumToString() ? mapOfEnumToStringAsStrings() : null) - .add("MapOfStringToEnum", hasMapOfStringToEnum() ? mapOfStringToEnumAsStrings() : null) - .add("MapOfEnumToSimpleStruct", hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null) - .add("MapOfEnumToListOfEnums", hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null) - .add("MapOfEnumToMapOfStringToEnum", - hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null) - .add("TimestampMember", timestampMember()) - .add("StructWithNestedTimestampMember", structWithNestedTimestampMember()).add("BlobArg", blobArg()) - .add("StructWithNestedBlob", structWithNestedBlob()).add("BlobMap", hasBlobMap() ? blobMap() : null) - .add("ListOfBlobs", hasListOfBlobs() ? listOfBlobs() : null).add("RecursiveStruct", recursiveStruct()) - .add("PolymorphicTypeWithSubTypes", polymorphicTypeWithSubTypes()) - .add("PolymorphicTypeWithoutSubTypes", polymorphicTypeWithoutSubTypes()).add("EnumType", enumTypeAsString()) - .add("Underscore_Name_Type", underscore_Name_Type()).add("MyDocument", myDocument()) - .add("AllTypesUnionStructure", allTypesUnionStructure()).build(); + .builder("AllTypesRequest") + .add("StringMember", stringMember()) + .add("IntegerMember", integerMember()) + .add("BooleanMember", booleanMember()) + .add("FloatMember", floatMember()) + .add("DoubleMember", doubleMember()) + .add("LongMember", longMember()) + .add("ShortMember", shortMember()) + .add("ByteMember", byteMember()) + .add("SimpleList", hasSimpleList() ? simpleList() : null) + .add("ListOfEnums", hasListOfEnums() ? listOfEnumsAsStrings() : null) + .add("ListOfMaps", hasListOfMaps() ? listOfMaps() : null) + .add("ListOfStructs", hasListOfStructs() ? listOfStructs() : null) + .add("ListOfMapOfEnumToString", hasListOfMapOfEnumToString() ? listOfMapOfEnumToStringAsStrings() : null) + .add("ListOfMapOfStringToStruct", hasListOfMapOfStringToStruct() ? listOfMapOfStringToStruct() : null) + .add("MapOfStringToIntegerList", hasMapOfStringToIntegerList() ? mapOfStringToIntegerList() : null) + .add("MapOfStringToString", hasMapOfStringToString() ? mapOfStringToString() : null) + .add("MapOfStringToSimpleStruct", hasMapOfStringToSimpleStruct() ? mapOfStringToSimpleStruct() : null) + .add("MapOfEnumToEnum", hasMapOfEnumToEnum() ? mapOfEnumToEnumAsStrings() : null) + .add("MapOfEnumToString", hasMapOfEnumToString() ? mapOfEnumToStringAsStrings() : null) + .add("MapOfStringToEnum", hasMapOfStringToEnum() ? mapOfStringToEnumAsStrings() : null) + .add("MapOfEnumToSimpleStruct", hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null) + .add("MapOfEnumToListOfEnums", hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null) + .add("MapOfEnumToMapOfStringToEnum", + hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null) + .add("TimestampMember", timestampMember()) + .add("StructWithNestedTimestampMember", structWithNestedTimestampMember()).add("BlobArg", blobArg()) + .add("StructWithNestedBlob", structWithNestedBlob()).add("BlobMap", hasBlobMap() ? blobMap() : null) + .add("ListOfBlobs", hasListOfBlobs() ? listOfBlobs() : null).add("RecursiveStruct", recursiveStruct()) + .add("PolymorphicTypeWithSubTypes", polymorphicTypeWithSubTypes()) + .add("PolymorphicTypeWithoutSubTypes", polymorphicTypeWithoutSubTypes()).add("EnumType", enumTypeAsString()) + .add("Underscore_Name_Type", underscore_Name_Type()).add("MyDocument", myDocument()) + .add("AllTypesUnionStructure", allTypesUnionStructure()).build(); } public final Optional getValueForField(String fieldName, Class clazz) { switch (fieldName) { - case "StringMember": - return Optional.ofNullable(clazz.cast(stringMember())); - case "IntegerMember": - return Optional.ofNullable(clazz.cast(integerMember())); - case "BooleanMember": - return Optional.ofNullable(clazz.cast(booleanMember())); - case "FloatMember": - return Optional.ofNullable(clazz.cast(floatMember())); - case "DoubleMember": - return Optional.ofNullable(clazz.cast(doubleMember())); - case "LongMember": - return Optional.ofNullable(clazz.cast(longMember())); - case "ShortMember": - return Optional.ofNullable(clazz.cast(shortMember())); - case "SimpleList": - return Optional.ofNullable(clazz.cast(simpleList())); - case "ListOfEnums": - return Optional.ofNullable(clazz.cast(listOfEnumsAsStrings())); - case "ListOfMaps": - return Optional.ofNullable(clazz.cast(listOfMaps())); - case "ListOfStructs": - return Optional.ofNullable(clazz.cast(listOfStructs())); - case "ListOfMapOfEnumToString": - return Optional.ofNullable(clazz.cast(listOfMapOfEnumToStringAsStrings())); - case "ListOfMapOfStringToStruct": - return Optional.ofNullable(clazz.cast(listOfMapOfStringToStruct())); - case "MapOfStringToIntegerList": - return Optional.ofNullable(clazz.cast(mapOfStringToIntegerList())); - case "MapOfStringToString": - return Optional.ofNullable(clazz.cast(mapOfStringToString())); - case "MapOfStringToSimpleStruct": - return Optional.ofNullable(clazz.cast(mapOfStringToSimpleStruct())); - case "MapOfEnumToEnum": - return Optional.ofNullable(clazz.cast(mapOfEnumToEnumAsStrings())); - case "MapOfEnumToString": - return Optional.ofNullable(clazz.cast(mapOfEnumToStringAsStrings())); - case "MapOfStringToEnum": - return Optional.ofNullable(clazz.cast(mapOfStringToEnumAsStrings())); - case "MapOfEnumToSimpleStruct": - return Optional.ofNullable(clazz.cast(mapOfEnumToSimpleStructAsStrings())); - case "MapOfEnumToListOfEnums": - return Optional.ofNullable(clazz.cast(mapOfEnumToListOfEnumsAsStrings())); - case "MapOfEnumToMapOfStringToEnum": - return Optional.ofNullable(clazz.cast(mapOfEnumToMapOfStringToEnumAsStrings())); - case "TimestampMember": - return Optional.ofNullable(clazz.cast(timestampMember())); - case "StructWithNestedTimestampMember": - return Optional.ofNullable(clazz.cast(structWithNestedTimestampMember())); - case "BlobArg": - return Optional.ofNullable(clazz.cast(blobArg())); - case "StructWithNestedBlob": - return Optional.ofNullable(clazz.cast(structWithNestedBlob())); - case "BlobMap": - return Optional.ofNullable(clazz.cast(blobMap())); - case "ListOfBlobs": - return Optional.ofNullable(clazz.cast(listOfBlobs())); - case "RecursiveStruct": - return Optional.ofNullable(clazz.cast(recursiveStruct())); - case "PolymorphicTypeWithSubTypes": - return Optional.ofNullable(clazz.cast(polymorphicTypeWithSubTypes())); - case "PolymorphicTypeWithoutSubTypes": - return Optional.ofNullable(clazz.cast(polymorphicTypeWithoutSubTypes())); - case "EnumType": - return Optional.ofNullable(clazz.cast(enumTypeAsString())); - case "Underscore_Name_Type": - return Optional.ofNullable(clazz.cast(underscore_Name_Type())); - case "MyDocument": - return Optional.ofNullable(clazz.cast(myDocument())); - case "AllTypesUnionStructure": - return Optional.ofNullable(clazz.cast(allTypesUnionStructure())); - default: - return Optional.empty(); + case "StringMember": + return Optional.ofNullable(clazz.cast(stringMember())); + case "IntegerMember": + return Optional.ofNullable(clazz.cast(integerMember())); + case "BooleanMember": + return Optional.ofNullable(clazz.cast(booleanMember())); + case "FloatMember": + return Optional.ofNullable(clazz.cast(floatMember())); + case "DoubleMember": + return Optional.ofNullable(clazz.cast(doubleMember())); + case "LongMember": + return Optional.ofNullable(clazz.cast(longMember())); + case "ShortMember": + return Optional.ofNullable(clazz.cast(shortMember())); + case "ByteMember": + return Optional.ofNullable(clazz.cast(byteMember())); + case "SimpleList": + return Optional.ofNullable(clazz.cast(simpleList())); + case "ListOfEnums": + return Optional.ofNullable(clazz.cast(listOfEnumsAsStrings())); + case "ListOfMaps": + return Optional.ofNullable(clazz.cast(listOfMaps())); + case "ListOfStructs": + return Optional.ofNullable(clazz.cast(listOfStructs())); + case "ListOfMapOfEnumToString": + return Optional.ofNullable(clazz.cast(listOfMapOfEnumToStringAsStrings())); + case "ListOfMapOfStringToStruct": + return Optional.ofNullable(clazz.cast(listOfMapOfStringToStruct())); + case "MapOfStringToIntegerList": + return Optional.ofNullable(clazz.cast(mapOfStringToIntegerList())); + case "MapOfStringToString": + return Optional.ofNullable(clazz.cast(mapOfStringToString())); + case "MapOfStringToSimpleStruct": + return Optional.ofNullable(clazz.cast(mapOfStringToSimpleStruct())); + case "MapOfEnumToEnum": + return Optional.ofNullable(clazz.cast(mapOfEnumToEnumAsStrings())); + case "MapOfEnumToString": + return Optional.ofNullable(clazz.cast(mapOfEnumToStringAsStrings())); + case "MapOfStringToEnum": + return Optional.ofNullable(clazz.cast(mapOfStringToEnumAsStrings())); + case "MapOfEnumToSimpleStruct": + return Optional.ofNullable(clazz.cast(mapOfEnumToSimpleStructAsStrings())); + case "MapOfEnumToListOfEnums": + return Optional.ofNullable(clazz.cast(mapOfEnumToListOfEnumsAsStrings())); + case "MapOfEnumToMapOfStringToEnum": + return Optional.ofNullable(clazz.cast(mapOfEnumToMapOfStringToEnumAsStrings())); + case "TimestampMember": + return Optional.ofNullable(clazz.cast(timestampMember())); + case "StructWithNestedTimestampMember": + return Optional.ofNullable(clazz.cast(structWithNestedTimestampMember())); + case "BlobArg": + return Optional.ofNullable(clazz.cast(blobArg())); + case "StructWithNestedBlob": + return Optional.ofNullable(clazz.cast(structWithNestedBlob())); + case "BlobMap": + return Optional.ofNullable(clazz.cast(blobMap())); + case "ListOfBlobs": + return Optional.ofNullable(clazz.cast(listOfBlobs())); + case "RecursiveStruct": + return Optional.ofNullable(clazz.cast(recursiveStruct())); + case "PolymorphicTypeWithSubTypes": + return Optional.ofNullable(clazz.cast(polymorphicTypeWithSubTypes())); + case "PolymorphicTypeWithoutSubTypes": + return Optional.ofNullable(clazz.cast(polymorphicTypeWithoutSubTypes())); + case "EnumType": + return Optional.ofNullable(clazz.cast(enumTypeAsString())); + case "Underscore_Name_Type": + return Optional.ofNullable(clazz.cast(underscore_Name_Type())); + case "MyDocument": + return Optional.ofNullable(clazz.cast(myDocument())); + case "AllTypesUnionStructure": + return Optional.ofNullable(clazz.cast(allTypesUnionStructure())); + default: + return Optional.empty(); } } @@ -1655,6 +1676,15 @@ public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, Copy */ Builder shortMember(Short shortMember); + /** + * Sets the value of the ByteMember property for this object. + * + * @param byteMember + * The new value for the ByteMember property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder byteMember(Byte byteMember); + /** * Sets the value of the SimpleList property for this object. * @@ -1757,7 +1787,7 @@ public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, Copy * When the {@link Consumer} completes, * {@link software.amazon.awssdk.services.jsonprotocoltests.model.SimpleStruct.Builder#build()} is called * immediately and its result is passed to {@link #listOfStructs(List)}. - * + * * @param listOfStructs * a consumer that will call methods on * {@link software.amazon.awssdk.services.jsonprotocoltests.model.SimpleStruct.Builder} @@ -1964,7 +1994,7 @@ public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, Copy *

* When the {@link Consumer} completes, {@link StructWithTimestamp.Builder#build()} is called immediately and * its result is passed to {@link #structWithNestedTimestampMember(StructWithTimestamp)}. - * + * * @param structWithNestedTimestampMember * a consumer that will call methods on {@link StructWithTimestamp.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -1972,7 +2002,7 @@ public interface Builder extends JsonProtocolTestsRequest.Builder, SdkPojo, Copy */ default Builder structWithNestedTimestampMember(Consumer structWithNestedTimestampMember) { return structWithNestedTimestampMember(StructWithTimestamp.builder().applyMutation(structWithNestedTimestampMember) - .build()); + .build()); } /** @@ -2002,7 +2032,7 @@ default Builder structWithNestedTimestampMember(Consumer * When the {@link Consumer} completes, {@link StructWithNestedBlobType.Builder#build()} is called immediately * and its result is passed to {@link #structWithNestedBlob(StructWithNestedBlobType)}. - * + * * @param structWithNestedBlob * a consumer that will call methods on {@link StructWithNestedBlobType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2057,7 +2087,7 @@ default Builder structWithNestedBlob(Consumer *

* When the {@link Consumer} completes, {@link RecursiveStructType.Builder#build()} is called immediately and * its result is passed to {@link #recursiveStruct(RecursiveStructType)}. - * + * * @param recursiveStruct * a consumer that will call methods on {@link RecursiveStructType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2085,7 +2115,7 @@ default Builder recursiveStruct(Consumer recursiveS *

* When the {@link Consumer} completes, {@link BaseType.Builder#build()} is called immediately and its result is * passed to {@link #polymorphicTypeWithSubTypes(BaseType)}. - * + * * @param polymorphicTypeWithSubTypes * a consumer that will call methods on {@link BaseType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2113,7 +2143,7 @@ default Builder polymorphicTypeWithSubTypes(Consumer polymorph *

* When the {@link Consumer} completes, {@link SubTypeOne.Builder#build()} is called immediately and its result * is passed to {@link #polymorphicTypeWithoutSubTypes(SubTypeOne)}. - * + * * @param polymorphicTypeWithoutSubTypes * a consumer that will call methods on {@link SubTypeOne.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2163,7 +2193,7 @@ default Builder polymorphicTypeWithoutSubTypes(Consumer poly *

* When the {@link Consumer} completes, {@link Underscore_Name_Type.Builder#build()} is called immediately and * its result is passed to {@link #underscore_Name_Type(Underscore_Name_Type)}. - * + * * @param underscore_Name_Type * a consumer that will call methods on {@link Underscore_Name_Type.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2200,7 +2230,7 @@ default Builder underscore_Name_Type(Consumer unde *

* When the {@link Consumer} completes, {@link AllTypesUnionStructure.Builder#build()} is called immediately and * its result is passed to {@link #allTypesUnionStructure(AllTypesUnionStructure)}. - * + * * @param allTypesUnionStructure * a consumer that will call methods on {@link AllTypesUnionStructure.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2232,6 +2262,8 @@ static final class BuilderImpl extends JsonProtocolTestsRequest.BuilderImpl impl private Short shortMember; + private Byte byteMember; + private List simpleList = DefaultSdkAutoConstructList.getInstance(); private List listOfEnums = DefaultSdkAutoConstructList.getInstance(); @@ -2300,6 +2332,7 @@ private BuilderImpl(AllTypesRequest model) { doubleMember(model.doubleMember); longMember(model.longMember); shortMember(model.shortMember); + byteMember(model.byteMember); simpleList(model.simpleList); listOfEnumsWithStrings(model.listOfEnums); listOfMaps(model.listOfMaps); @@ -2428,6 +2461,20 @@ public final Builder shortMember(Short shortMember) { return this; } + public final Byte getByteMember() { + return byteMember; + } + + public final void setByteMember(Byte byteMember) { + this.byteMember = byteMember; + } + + @Override + public final Builder byteMember(Byte byteMember) { + this.byteMember = byteMember; + return this; + } + public final Collection getSimpleList() { if (simpleList instanceof SdkAutoConstructList) { return null; @@ -2542,7 +2589,7 @@ public final Builder listOfStructs(SimpleStruct... listOfStructs) { @SafeVarargs public final Builder listOfStructs(Consumer... listOfStructs) { listOfStructs(Stream.of(listOfStructs).map(c -> SimpleStruct.builder().applyMutation(c).build()) - .collect(Collectors.toList())); + .collect(Collectors.toList())); return this; } @@ -2572,7 +2619,7 @@ public final Builder listOfMapOfEnumToStringWithStrings(Map... l public final List> getListOfMapOfStringToStruct() { List> result = ListOfMapOfStringToStructCopier - .copyToBuilder(this.listOfMapOfStringToStruct); + .copyToBuilder(this.listOfMapOfStringToStruct); if (result instanceof SdkAutoConstructList) { return null; } @@ -2580,7 +2627,7 @@ public final List> getListOfMapOfStringToStruc } public final void setListOfMapOfStringToStruct( - Collection> listOfMapOfStringToStruct) { + Collection> listOfMapOfStringToStruct) { this.listOfMapOfStringToStruct = ListOfMapOfStringToStructCopier.copyFromBuilder(listOfMapOfStringToStruct); } @@ -2633,7 +2680,7 @@ public final Builder mapOfStringToString(Map mapOfStringToString public final Map getMapOfStringToSimpleStruct() { Map result = MapOfStringToSimpleStructCopier - .copyToBuilder(this.mapOfStringToSimpleStruct); + .copyToBuilder(this.mapOfStringToSimpleStruct); if (result instanceof SdkAutoConstructMap) { return null; } @@ -2779,14 +2826,14 @@ public final void setMapOfEnumToMapOfStringToEnum(Map> mapOfEnumToMapOfStringToEnum) { + Map> mapOfEnumToMapOfStringToEnum) { this.mapOfEnumToMapOfStringToEnum = MapOfEnumToMapOfStringToEnumCopier.copy(mapOfEnumToMapOfStringToEnum); return this; } @Override public final Builder mapOfEnumToMapOfStringToEnum( - Map> mapOfEnumToMapOfStringToEnum) { + Map> mapOfEnumToMapOfStringToEnum) { this.mapOfEnumToMapOfStringToEnum = MapOfEnumToMapOfStringToEnumCopier.copyEnumToString(mapOfEnumToMapOfStringToEnum); return this; } @@ -2811,7 +2858,7 @@ public final StructWithTimestamp.Builder getStructWithNestedTimestampMember() { public final void setStructWithNestedTimestampMember(StructWithTimestamp.BuilderImpl structWithNestedTimestampMember) { this.structWithNestedTimestampMember = structWithNestedTimestampMember != null ? structWithNestedTimestampMember - .build() : null; + .build() : null; } @Override @@ -2853,12 +2900,12 @@ public final Map getBlobMap() { return null; } return blobMap == null ? null : blobMap.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().asByteBuffer())); + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().asByteBuffer())); } public final void setBlobMap(Map blobMap) { blobMap(blobMap == null ? null : blobMap.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> SdkBytes.fromByteBuffer(e.getValue())))); + .collect(Collectors.toMap(e -> e.getKey(), e -> SdkBytes.fromByteBuffer(e.getValue())))); } @Override @@ -2876,7 +2923,7 @@ public final List getListOfBlobs() { public final void setListOfBlobs(Collection listOfBlobs) { listOfBlobs(listOfBlobs == null ? null : listOfBlobs.stream().map(SdkBytes::fromByteBuffer) - .collect(Collectors.toList())); + .collect(Collectors.toList())); } @Override @@ -2926,7 +2973,7 @@ public final SubTypeOne.Builder getPolymorphicTypeWithoutSubTypes() { public final void setPolymorphicTypeWithoutSubTypes(SubTypeOne.BuilderImpl polymorphicTypeWithoutSubTypes) { this.polymorphicTypeWithoutSubTypes = polymorphicTypeWithoutSubTypes != null ? polymorphicTypeWithoutSubTypes.build() - : null; + : null; } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesresponse.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesresponse.java index ea1c98f4518b..27335cef0cec 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesresponse.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/alltypesresponse.java @@ -36,414 +36,418 @@ */ @Generated("software.amazon.awssdk:codegen") public final class AllTypesResponse extends JsonProtocolTestsResponse implements - ToCopyableBuilder { + ToCopyableBuilder { private static final SdkField STRING_MEMBER_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("StringMember").getter(getter(AllTypesResponse::stringMember)).setter(setter(Builder::stringMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StringMember").build()).build(); + .memberName("StringMember").getter(getter(AllTypesResponse::stringMember)).setter(setter(Builder::stringMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StringMember").build()).build(); private static final SdkField INTEGER_MEMBER_FIELD = SdkField. builder(MarshallingType.INTEGER) - .memberName("IntegerMember").getter(getter(AllTypesResponse::integerMember)).setter(setter(Builder::integerMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("IntegerMember").build()).build(); + .memberName("IntegerMember").getter(getter(AllTypesResponse::integerMember)).setter(setter(Builder::integerMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("IntegerMember").build()).build(); private static final SdkField BOOLEAN_MEMBER_FIELD = SdkField. builder(MarshallingType.BOOLEAN) - .memberName("BooleanMember").getter(getter(AllTypesResponse::booleanMember)).setter(setter(Builder::booleanMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BooleanMember").build()).build(); + .memberName("BooleanMember").getter(getter(AllTypesResponse::booleanMember)).setter(setter(Builder::booleanMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BooleanMember").build()).build(); private static final SdkField FLOAT_MEMBER_FIELD = SdkField. builder(MarshallingType.FLOAT) - .memberName("FloatMember").getter(getter(AllTypesResponse::floatMember)).setter(setter(Builder::floatMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("FloatMember").build()).build(); + .memberName("FloatMember").getter(getter(AllTypesResponse::floatMember)).setter(setter(Builder::floatMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("FloatMember").build()).build(); private static final SdkField DOUBLE_MEMBER_FIELD = SdkField. builder(MarshallingType.DOUBLE) - .memberName("DoubleMember").getter(getter(AllTypesResponse::doubleMember)).setter(setter(Builder::doubleMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("DoubleMember").build()).build(); + .memberName("DoubleMember").getter(getter(AllTypesResponse::doubleMember)).setter(setter(Builder::doubleMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("DoubleMember").build()).build(); private static final SdkField LONG_MEMBER_FIELD = SdkField. builder(MarshallingType.LONG) - .memberName("LongMember").getter(getter(AllTypesResponse::longMember)).setter(setter(Builder::longMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("LongMember").build()).build(); + .memberName("LongMember").getter(getter(AllTypesResponse::longMember)).setter(setter(Builder::longMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("LongMember").build()).build(); private static final SdkField SHORT_MEMBER_FIELD = SdkField. builder(MarshallingType.SHORT) - .memberName("ShortMember").getter(getter(AllTypesResponse::shortMember)).setter(setter(Builder::shortMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ShortMember").build()).build(); + .memberName("ShortMember").getter(getter(AllTypesResponse::shortMember)).setter(setter(Builder::shortMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ShortMember").build()).build(); + + private static final SdkField BYTE_MEMBER_FIELD = SdkField. builder(MarshallingType.BYTE) + .memberName("ByteMember").getter(getter(AllTypesResponse::byteMember)).setter(setter(Builder::byteMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ByteMember").build()).build(); private static final SdkField> SIMPLE_LIST_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("SimpleList") - .getter(getter(AllTypesResponse::simpleList)) - .setter(setter(Builder::simpleList)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("SimpleList").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("SimpleList") + .getter(getter(AllTypesResponse::simpleList)) + .setter(setter(Builder::simpleList)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("SimpleList").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField> LIST_OF_ENUMS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfEnums") - .getter(getter(AllTypesResponse::listOfEnumsAsStrings)) - .setter(setter(Builder::listOfEnumsWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfEnums").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfEnums") + .getter(getter(AllTypesResponse::listOfEnumsAsStrings)) + .setter(setter(Builder::listOfEnumsWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfEnums").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAPS_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMaps") - .getter(getter(AllTypesResponse::listOfMaps)) - .setter(setter(Builder::listOfMaps)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMaps").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMaps") + .getter(getter(AllTypesResponse::listOfMaps)) + .setter(setter(Builder::listOfMaps)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMaps").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField> LIST_OF_STRUCTS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfStructs") - .getter(getter(AllTypesResponse::listOfStructs)) - .setter(setter(Builder::listOfStructs)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfStructs").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfStructs") + .getter(getter(AllTypesResponse::listOfStructs)) + .setter(setter(Builder::listOfStructs)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfStructs").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMapOfEnumToString") - .getter(getter(AllTypesResponse::listOfMapOfEnumToStringAsStrings)) - .setter(setter(Builder::listOfMapOfEnumToStringWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfEnumToString").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMapOfEnumToString") + .getter(getter(AllTypesResponse::listOfMapOfEnumToStringAsStrings)) + .setter(setter(Builder::listOfMapOfEnumToStringWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfEnumToString").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD = SdkField - .>> builder(MarshallingType.LIST) - .memberName("ListOfMapOfStringToStruct") - .getter(getter(AllTypesResponse::listOfMapOfStringToStruct)) - .setter(setter(Builder::listOfMapOfStringToStruct)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfStringToStruct").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.LIST) + .memberName("ListOfMapOfStringToStruct") + .getter(getter(AllTypesResponse::listOfMapOfStringToStruct)) + .setter(setter(Builder::listOfMapOfStringToStruct)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfMapOfStringToStruct").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> MAP_OF_STRING_TO_INTEGER_LIST_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfStringToIntegerList") - .getter(getter(AllTypesResponse::mapOfStringToIntegerList)) - .setter(setter(Builder::mapOfStringToIntegerList)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToIntegerList").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.LIST) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.INTEGER) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfStringToIntegerList") + .getter(getter(AllTypesResponse::mapOfStringToIntegerList)) + .setter(setter(Builder::mapOfStringToIntegerList)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToIntegerList").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.LIST) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.INTEGER) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()) + .build()).build()).build()).build(); private static final SdkField> MAP_OF_STRING_TO_STRING_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToString") - .getter(getter(AllTypesResponse::mapOfStringToString)) - .setter(setter(Builder::mapOfStringToString)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToString").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToString") + .getter(getter(AllTypesResponse::mapOfStringToString)) + .setter(setter(Builder::mapOfStringToString)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToString").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 SdkField> MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToSimpleStruct") - .getter(getter(AllTypesResponse::mapOfStringToSimpleStruct)) - .setter(setter(Builder::mapOfStringToSimpleStruct)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToSimpleStruct").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToSimpleStruct") + .getter(getter(AllTypesResponse::mapOfStringToSimpleStruct)) + .setter(setter(Builder::mapOfStringToSimpleStruct)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToSimpleStruct").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField> MAP_OF_ENUM_TO_ENUM_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToEnum") - .getter(getter(AllTypesResponse::mapOfEnumToEnumAsStrings)) - .setter(setter(Builder::mapOfEnumToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToEnum").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToEnum") + .getter(getter(AllTypesResponse::mapOfEnumToEnumAsStrings)) + .setter(setter(Builder::mapOfEnumToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToEnum").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 SdkField> MAP_OF_ENUM_TO_STRING_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToString") - .getter(getter(AllTypesResponse::mapOfEnumToStringAsStrings)) - .setter(setter(Builder::mapOfEnumToStringWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToString").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToString") + .getter(getter(AllTypesResponse::mapOfEnumToStringAsStrings)) + .setter(setter(Builder::mapOfEnumToStringWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToString").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 SdkField> MAP_OF_STRING_TO_ENUM_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfStringToEnum") - .getter(getter(AllTypesResponse::mapOfStringToEnumAsStrings)) - .setter(setter(Builder::mapOfStringToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToEnum").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfStringToEnum") + .getter(getter(AllTypesResponse::mapOfStringToEnumAsStrings)) + .setter(setter(Builder::mapOfStringToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfStringToEnum").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 SdkField> MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("MapOfEnumToSimpleStruct") - .getter(getter(AllTypesResponse::mapOfEnumToSimpleStructAsStrings)) - .setter(setter(Builder::mapOfEnumToSimpleStructWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToSimpleStruct").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_POJO) - .constructor(SimpleStruct::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("MapOfEnumToSimpleStruct") + .getter(getter(AllTypesResponse::mapOfEnumToSimpleStructAsStrings)) + .setter(setter(Builder::mapOfEnumToSimpleStructWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToSimpleStruct").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_POJO) + .constructor(SimpleStruct::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField>> MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfEnumToListOfEnums") - .getter(getter(AllTypesResponse::mapOfEnumToListOfEnumsAsStrings)) - .setter(setter(Builder::mapOfEnumToListOfEnumsWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToListOfEnums").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.LIST) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfEnumToListOfEnums") + .getter(getter(AllTypesResponse::mapOfEnumToListOfEnumsAsStrings)) + .setter(setter(Builder::mapOfEnumToListOfEnumsWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToListOfEnums").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.LIST) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()) + .build()).build()).build()).build(); private static final SdkField>> MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD = SdkField - .>> builder(MarshallingType.MAP) - .memberName("MapOfEnumToMapOfStringToEnum") - .getter(getter(AllTypesResponse::mapOfEnumToMapOfStringToEnumAsStrings)) - .setter(setter(Builder::mapOfEnumToMapOfStringToEnumWithStrings)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToMapOfStringToEnum") - .build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField.> builder(MarshallingType.MAP) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.STRING) - .traits(LocationTrait.builder() - .location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()) - .build()).build()).build()).build(); + .>> builder(MarshallingType.MAP) + .memberName("MapOfEnumToMapOfStringToEnum") + .getter(getter(AllTypesResponse::mapOfEnumToMapOfStringToEnumAsStrings)) + .setter(setter(Builder::mapOfEnumToMapOfStringToEnumWithStrings)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MapOfEnumToMapOfStringToEnum") + .build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField.> builder(MarshallingType.MAP) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.STRING) + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()) + .build()).build()).build()).build(); private static final SdkField TIMESTAMP_MEMBER_FIELD = SdkField. builder(MarshallingType.INSTANT) - .memberName("TimestampMember").getter(getter(AllTypesResponse::timestampMember)) - .setter(setter(Builder::timestampMember)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("TimestampMember").build()).build(); + .memberName("TimestampMember").getter(getter(AllTypesResponse::timestampMember)) + .setter(setter(Builder::timestampMember)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("TimestampMember").build()).build(); private static final SdkField STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("StructWithNestedTimestampMember") - .getter(getter(AllTypesResponse::structWithNestedTimestampMember)) - .setter(setter(Builder::structWithNestedTimestampMember)) - .constructor(StructWithTimestamp::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedTimestampMember") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("StructWithNestedTimestampMember") + .getter(getter(AllTypesResponse::structWithNestedTimestampMember)) + .setter(setter(Builder::structWithNestedTimestampMember)) + .constructor(StructWithTimestamp::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedTimestampMember") + .build()).build(); private static final SdkField BLOB_ARG_FIELD = SdkField. builder(MarshallingType.SDK_BYTES) - .memberName("BlobArg").getter(getter(AllTypesResponse::blobArg)).setter(setter(Builder::blobArg)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobArg").build()).build(); + .memberName("BlobArg").getter(getter(AllTypesResponse::blobArg)).setter(setter(Builder::blobArg)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobArg").build()).build(); private static final SdkField STRUCT_WITH_NESTED_BLOB_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("StructWithNestedBlob") - .getter(getter(AllTypesResponse::structWithNestedBlob)).setter(setter(Builder::structWithNestedBlob)) - .constructor(StructWithNestedBlobType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedBlob").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("StructWithNestedBlob") + .getter(getter(AllTypesResponse::structWithNestedBlob)).setter(setter(Builder::structWithNestedBlob)) + .constructor(StructWithNestedBlobType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("StructWithNestedBlob").build()) + .build(); private static final SdkField> BLOB_MAP_FIELD = SdkField - .> builder(MarshallingType.MAP) - .memberName("BlobMap") - .getter(getter(AllTypesResponse::blobMap)) - .setter(setter(Builder::blobMap)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobMap").build(), - MapTrait.builder() - .keyLocationName("key") - .valueLocationName("value") - .valueFieldInfo( - SdkField. builder(MarshallingType.SDK_BYTES) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("value").build()).build()).build()).build(); + .> builder(MarshallingType.MAP) + .memberName("BlobMap") + .getter(getter(AllTypesResponse::blobMap)) + .setter(setter(Builder::blobMap)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("BlobMap").build(), + MapTrait.builder() + .keyLocationName("key") + .valueLocationName("value") + .valueFieldInfo( + SdkField. builder(MarshallingType.SDK_BYTES) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("value").build()).build()).build()).build(); private static final SdkField> LIST_OF_BLOBS_FIELD = SdkField - .> builder(MarshallingType.LIST) - .memberName("ListOfBlobs") - .getter(getter(AllTypesResponse::listOfBlobs)) - .setter(setter(Builder::listOfBlobs)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfBlobs").build(), - ListTrait - .builder() - .memberLocationName(null) - .memberFieldInfo( - SdkField. builder(MarshallingType.SDK_BYTES) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) - .locationName("member").build()).build()).build()).build(); + .> builder(MarshallingType.LIST) + .memberName("ListOfBlobs") + .getter(getter(AllTypesResponse::listOfBlobs)) + .setter(setter(Builder::listOfBlobs)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ListOfBlobs").build(), + ListTrait + .builder() + .memberLocationName(null) + .memberFieldInfo( + SdkField. builder(MarshallingType.SDK_BYTES) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD) + .locationName("member").build()).build()).build()).build(); private static final SdkField RECURSIVE_STRUCT_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("RecursiveStruct") - .getter(getter(AllTypesResponse::recursiveStruct)).setter(setter(Builder::recursiveStruct)) - .constructor(RecursiveStructType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("RecursiveStruct").build()).build(); + . builder(MarshallingType.SDK_POJO).memberName("RecursiveStruct") + .getter(getter(AllTypesResponse::recursiveStruct)).setter(setter(Builder::recursiveStruct)) + .constructor(RecursiveStructType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("RecursiveStruct").build()).build(); private static final SdkField POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("PolymorphicTypeWithSubTypes") - .getter(getter(AllTypesResponse::polymorphicTypeWithSubTypes)) - .setter(setter(Builder::polymorphicTypeWithSubTypes)) - .constructor(BaseType::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithSubTypes") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("PolymorphicTypeWithSubTypes") + .getter(getter(AllTypesResponse::polymorphicTypeWithSubTypes)) + .setter(setter(Builder::polymorphicTypeWithSubTypes)) + .constructor(BaseType::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithSubTypes") + .build()).build(); private static final SdkField POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD = SdkField - . builder(MarshallingType.SDK_POJO) - .memberName("PolymorphicTypeWithoutSubTypes") - .getter(getter(AllTypesResponse::polymorphicTypeWithoutSubTypes)) - .setter(setter(Builder::polymorphicTypeWithoutSubTypes)) - .constructor(SubTypeOne::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithoutSubTypes") - .build()).build(); + . builder(MarshallingType.SDK_POJO) + .memberName("PolymorphicTypeWithoutSubTypes") + .getter(getter(AllTypesResponse::polymorphicTypeWithoutSubTypes)) + .setter(setter(Builder::polymorphicTypeWithoutSubTypes)) + .constructor(SubTypeOne::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("PolymorphicTypeWithoutSubTypes") + .build()).build(); private static final SdkField ENUM_TYPE_FIELD = SdkField. builder(MarshallingType.STRING) - .memberName("EnumType").getter(getter(AllTypesResponse::enumTypeAsString)).setter(setter(Builder::enumType)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("EnumType").build()).build(); + .memberName("EnumType").getter(getter(AllTypesResponse::enumTypeAsString)).setter(setter(Builder::enumType)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("EnumType").build()).build(); private static final SdkField UNDERSCORE_NAME_TYPE_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("Underscore_Name_Type") - .getter(getter(AllTypesResponse::underscore_Name_Type)).setter(setter(Builder::underscore_Name_Type)) - .constructor(Underscore_Name_Type::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("Underscore_Name_Type").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("Underscore_Name_Type") + .getter(getter(AllTypesResponse::underscore_Name_Type)).setter(setter(Builder::underscore_Name_Type)) + .constructor(Underscore_Name_Type::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("Underscore_Name_Type").build()) + .build(); private static final SdkField MY_DOCUMENT_FIELD = SdkField. builder(MarshallingType.DOCUMENT) - .memberName("MyDocument").getter(getter(AllTypesResponse::myDocument)).setter(setter(Builder::myDocument)) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MyDocument").build()).build(); + .memberName("MyDocument").getter(getter(AllTypesResponse::myDocument)).setter(setter(Builder::myDocument)) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("MyDocument").build()).build(); private static final SdkField ALL_TYPES_UNION_STRUCTURE_FIELD = SdkField - . builder(MarshallingType.SDK_POJO).memberName("AllTypesUnionStructure") - .getter(getter(AllTypesResponse::allTypesUnionStructure)).setter(setter(Builder::allTypesUnionStructure)) - .constructor(AllTypesUnionStructure::builder) - .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("AllTypesUnionStructure").build()) - .build(); + . builder(MarshallingType.SDK_POJO).memberName("AllTypesUnionStructure") + .getter(getter(AllTypesResponse::allTypesUnionStructure)).setter(setter(Builder::allTypesUnionStructure)) + .constructor(AllTypesUnionStructure::builder) + .traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("AllTypesUnionStructure").build()) + .build(); private static final List> SDK_FIELDS = Collections.unmodifiableList(Arrays.asList(STRING_MEMBER_FIELD, - INTEGER_MEMBER_FIELD, BOOLEAN_MEMBER_FIELD, FLOAT_MEMBER_FIELD, DOUBLE_MEMBER_FIELD, LONG_MEMBER_FIELD, - SHORT_MEMBER_FIELD, SIMPLE_LIST_FIELD, LIST_OF_ENUMS_FIELD, LIST_OF_MAPS_FIELD, LIST_OF_STRUCTS_FIELD, - LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD, LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD, MAP_OF_STRING_TO_INTEGER_LIST_FIELD, - MAP_OF_STRING_TO_STRING_FIELD, MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD, MAP_OF_ENUM_TO_ENUM_FIELD, - MAP_OF_ENUM_TO_STRING_FIELD, MAP_OF_STRING_TO_ENUM_FIELD, MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD, - MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD, MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD, TIMESTAMP_MEMBER_FIELD, - STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD, BLOB_ARG_FIELD, STRUCT_WITH_NESTED_BLOB_FIELD, BLOB_MAP_FIELD, - LIST_OF_BLOBS_FIELD, RECURSIVE_STRUCT_FIELD, POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD, - POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD, ENUM_TYPE_FIELD, UNDERSCORE_NAME_TYPE_FIELD, MY_DOCUMENT_FIELD, - ALL_TYPES_UNION_STRUCTURE_FIELD)); + INTEGER_MEMBER_FIELD, BOOLEAN_MEMBER_FIELD, FLOAT_MEMBER_FIELD, DOUBLE_MEMBER_FIELD, LONG_MEMBER_FIELD, + SHORT_MEMBER_FIELD, BYTE_MEMBER_FIELD, SIMPLE_LIST_FIELD, LIST_OF_ENUMS_FIELD, LIST_OF_MAPS_FIELD, + LIST_OF_STRUCTS_FIELD, LIST_OF_MAP_OF_ENUM_TO_STRING_FIELD, LIST_OF_MAP_OF_STRING_TO_STRUCT_FIELD, + MAP_OF_STRING_TO_INTEGER_LIST_FIELD, MAP_OF_STRING_TO_STRING_FIELD, MAP_OF_STRING_TO_SIMPLE_STRUCT_FIELD, + MAP_OF_ENUM_TO_ENUM_FIELD, MAP_OF_ENUM_TO_STRING_FIELD, MAP_OF_STRING_TO_ENUM_FIELD, + MAP_OF_ENUM_TO_SIMPLE_STRUCT_FIELD, MAP_OF_ENUM_TO_LIST_OF_ENUMS_FIELD, MAP_OF_ENUM_TO_MAP_OF_STRING_TO_ENUM_FIELD, + TIMESTAMP_MEMBER_FIELD, STRUCT_WITH_NESTED_TIMESTAMP_MEMBER_FIELD, BLOB_ARG_FIELD, STRUCT_WITH_NESTED_BLOB_FIELD, + BLOB_MAP_FIELD, LIST_OF_BLOBS_FIELD, RECURSIVE_STRUCT_FIELD, POLYMORPHIC_TYPE_WITH_SUB_TYPES_FIELD, + POLYMORPHIC_TYPE_WITHOUT_SUB_TYPES_FIELD, ENUM_TYPE_FIELD, UNDERSCORE_NAME_TYPE_FIELD, MY_DOCUMENT_FIELD, + ALL_TYPES_UNION_STRUCTURE_FIELD)); private final String stringMember; @@ -459,6 +463,8 @@ SdkField. builder(MarshallingType.SDK_BYTES) private final Short shortMember; + private final Byte byteMember; + private final List simpleList; private final List listOfEnums; @@ -524,6 +530,7 @@ private AllTypesResponse(BuilderImpl builder) { this.doubleMember = builder.doubleMember; this.longMember = builder.longMember; this.shortMember = builder.shortMember; + this.byteMember = builder.byteMember; this.simpleList = builder.simpleList; this.listOfEnums = builder.listOfEnums; this.listOfMaps = builder.listOfMaps; @@ -556,7 +563,7 @@ private AllTypesResponse(BuilderImpl builder) { /** * Returns the value of the StringMember property for this object. - * + * * @return The value of the StringMember property for this object. */ public final String stringMember() { @@ -565,7 +572,7 @@ public final String stringMember() { /** * Returns the value of the IntegerMember property for this object. - * + * * @return The value of the IntegerMember property for this object. */ public final Integer integerMember() { @@ -574,7 +581,7 @@ public final Integer integerMember() { /** * Returns the value of the BooleanMember property for this object. - * + * * @return The value of the BooleanMember property for this object. */ public final Boolean booleanMember() { @@ -583,7 +590,7 @@ public final Boolean booleanMember() { /** * Returns the value of the FloatMember property for this object. - * + * * @return The value of the FloatMember property for this object. */ public final Float floatMember() { @@ -592,7 +599,7 @@ public final Float floatMember() { /** * Returns the value of the DoubleMember property for this object. - * + * * @return The value of the DoubleMember property for this object. */ public final Double doubleMember() { @@ -601,7 +608,7 @@ public final Double doubleMember() { /** * Returns the value of the LongMember property for this object. - * + * * @return The value of the LongMember property for this object. */ public final Long longMember() { @@ -610,13 +617,22 @@ public final Long longMember() { /** * Returns the value of the ShortMember property for this object. - * + * * @return The value of the ShortMember property for this object. */ public final Short shortMember() { return shortMember; } + /** + * Returns the value of the ByteMember property for this object. + * + * @return The value of the ByteMember property for this object. + */ + public final Byte byteMember() { + return byteMember; + } + /** * For responses, this returns true if the service returned a value for the SimpleList 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 @@ -638,7 +654,7 @@ public final boolean hasSimpleList() { * 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 #hasSimpleList} method. *

- * + * * @return The value of the SimpleList property for this object. */ public final List simpleList() { @@ -654,7 +670,7 @@ public final List simpleList() { * 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 #hasListOfEnums} method. *

- * + * * @return The value of the ListOfEnums property for this object. */ public final List listOfEnums() { @@ -682,7 +698,7 @@ public final boolean hasListOfEnums() { * 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 #hasListOfEnums} method. *

- * + * * @return The value of the ListOfEnums property for this object. */ public final List listOfEnumsAsStrings() { @@ -710,7 +726,7 @@ public final boolean hasListOfMaps() { * 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 #hasListOfMaps} method. *

- * + * * @return The value of the ListOfMaps property for this object. */ public final List> listOfMaps() { @@ -738,7 +754,7 @@ public final boolean hasListOfStructs() { * 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 #hasListOfStructs} method. *

- * + * * @return The value of the ListOfStructs property for this object. */ public final List listOfStructs() { @@ -754,7 +770,7 @@ public final List listOfStructs() { * 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 #hasListOfMapOfEnumToString} method. *

- * + * * @return The value of the ListOfMapOfEnumToString property for this object. */ public final List> listOfMapOfEnumToString() { @@ -782,7 +798,7 @@ public final boolean hasListOfMapOfEnumToString() { * 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 #hasListOfMapOfEnumToString} method. *

- * + * * @return The value of the ListOfMapOfEnumToString property for this object. */ public final List> listOfMapOfEnumToStringAsStrings() { @@ -810,7 +826,7 @@ public final boolean hasListOfMapOfStringToStruct() { * 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 #hasListOfMapOfStringToStruct} method. *

- * + * * @return The value of the ListOfMapOfStringToStruct property for this object. */ public final List> listOfMapOfStringToStruct() { @@ -838,7 +854,7 @@ public final boolean hasMapOfStringToIntegerList() { * 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 #hasMapOfStringToIntegerList} method. *

- * + * * @return The value of the MapOfStringToIntegerList property for this object. */ public final Map> mapOfStringToIntegerList() { @@ -866,7 +882,7 @@ public final boolean hasMapOfStringToString() { * 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 #hasMapOfStringToString} method. *

- * + * * @return The value of the MapOfStringToString property for this object. */ public final Map mapOfStringToString() { @@ -894,7 +910,7 @@ public final boolean hasMapOfStringToSimpleStruct() { * 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 #hasMapOfStringToSimpleStruct} method. *

- * + * * @return The value of the MapOfStringToSimpleStruct property for this object. */ public final Map mapOfStringToSimpleStruct() { @@ -910,7 +926,7 @@ public final Map mapOfStringToSimpleStruct() { * 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 #hasMapOfEnumToEnum} method. *

- * + * * @return The value of the MapOfEnumToEnum property for this object. */ public final Map mapOfEnumToEnum() { @@ -938,7 +954,7 @@ public final boolean hasMapOfEnumToEnum() { * 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 #hasMapOfEnumToEnum} method. *

- * + * * @return The value of the MapOfEnumToEnum property for this object. */ public final Map mapOfEnumToEnumAsStrings() { @@ -954,7 +970,7 @@ public final Map mapOfEnumToEnumAsStrings() { * 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 #hasMapOfEnumToString} method. *

- * + * * @return The value of the MapOfEnumToString property for this object. */ public final Map mapOfEnumToString() { @@ -982,7 +998,7 @@ public final boolean hasMapOfEnumToString() { * 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 #hasMapOfEnumToString} method. *

- * + * * @return The value of the MapOfEnumToString property for this object. */ public final Map mapOfEnumToStringAsStrings() { @@ -998,7 +1014,7 @@ public final Map mapOfEnumToStringAsStrings() { * 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 #hasMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfStringToEnum property for this object. */ public final Map mapOfStringToEnum() { @@ -1026,7 +1042,7 @@ public final boolean hasMapOfStringToEnum() { * 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 #hasMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfStringToEnum property for this object. */ public final Map mapOfStringToEnumAsStrings() { @@ -1042,7 +1058,7 @@ public final Map mapOfStringToEnumAsStrings() { * 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 #hasMapOfEnumToSimpleStruct} method. *

- * + * * @return The value of the MapOfEnumToSimpleStruct property for this object. */ public final Map mapOfEnumToSimpleStruct() { @@ -1070,7 +1086,7 @@ public final boolean hasMapOfEnumToSimpleStruct() { * 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 #hasMapOfEnumToSimpleStruct} method. *

- * + * * @return The value of the MapOfEnumToSimpleStruct property for this object. */ public final Map mapOfEnumToSimpleStructAsStrings() { @@ -1086,7 +1102,7 @@ public final Map mapOfEnumToSimpleStructAsStrings() { * 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 #hasMapOfEnumToListOfEnums} method. *

- * + * * @return The value of the MapOfEnumToListOfEnums property for this object. */ public final Map> mapOfEnumToListOfEnums() { @@ -1114,7 +1130,7 @@ public final boolean hasMapOfEnumToListOfEnums() { * 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 #hasMapOfEnumToListOfEnums} method. *

- * + * * @return The value of the MapOfEnumToListOfEnums property for this object. */ public final Map> mapOfEnumToListOfEnumsAsStrings() { @@ -1130,7 +1146,7 @@ public final Map> mapOfEnumToListOfEnumsAsStrings() { * 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 #hasMapOfEnumToMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfEnumToMapOfStringToEnum property for this object. */ public final Map> mapOfEnumToMapOfStringToEnum() { @@ -1158,7 +1174,7 @@ public final boolean hasMapOfEnumToMapOfStringToEnum() { * 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 #hasMapOfEnumToMapOfStringToEnum} method. *

- * + * * @return The value of the MapOfEnumToMapOfStringToEnum property for this object. */ public final Map> mapOfEnumToMapOfStringToEnumAsStrings() { @@ -1167,7 +1183,7 @@ public final Map> mapOfEnumToMapOfStringToEnumAsStri /** * Returns the value of the TimestampMember property for this object. - * + * * @return The value of the TimestampMember property for this object. */ public final Instant timestampMember() { @@ -1176,7 +1192,7 @@ public final Instant timestampMember() { /** * Returns the value of the StructWithNestedTimestampMember property for this object. - * + * * @return The value of the StructWithNestedTimestampMember property for this object. */ public final StructWithTimestamp structWithNestedTimestampMember() { @@ -1185,7 +1201,7 @@ public final StructWithTimestamp structWithNestedTimestampMember() { /** * Returns the value of the BlobArg property for this object. - * + * * @return The value of the BlobArg property for this object. */ public final SdkBytes blobArg() { @@ -1194,7 +1210,7 @@ public final SdkBytes blobArg() { /** * Returns the value of the StructWithNestedBlob property for this object. - * + * * @return The value of the StructWithNestedBlob property for this object. */ public final StructWithNestedBlobType structWithNestedBlob() { @@ -1222,7 +1238,7 @@ public final boolean hasBlobMap() { * 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 #hasBlobMap} method. *

- * + * * @return The value of the BlobMap property for this object. */ public final Map blobMap() { @@ -1250,7 +1266,7 @@ public final boolean hasListOfBlobs() { * 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 #hasListOfBlobs} method. *

- * + * * @return The value of the ListOfBlobs property for this object. */ public final List listOfBlobs() { @@ -1259,7 +1275,7 @@ public final List listOfBlobs() { /** * Returns the value of the RecursiveStruct property for this object. - * + * * @return The value of the RecursiveStruct property for this object. */ public final RecursiveStructType recursiveStruct() { @@ -1268,7 +1284,7 @@ public final RecursiveStructType recursiveStruct() { /** * Returns the value of the PolymorphicTypeWithSubTypes property for this object. - * + * * @return The value of the PolymorphicTypeWithSubTypes property for this object. */ public final BaseType polymorphicTypeWithSubTypes() { @@ -1277,7 +1293,7 @@ public final BaseType polymorphicTypeWithSubTypes() { /** * Returns the value of the PolymorphicTypeWithoutSubTypes property for this object. - * + * * @return The value of the PolymorphicTypeWithoutSubTypes property for this object. */ public final SubTypeOne polymorphicTypeWithoutSubTypes() { @@ -1291,7 +1307,7 @@ public final SubTypeOne polymorphicTypeWithoutSubTypes() { * return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from * {@link #enumTypeAsString}. *

- * + * * @return The value of the EnumType property for this object. * @see EnumType */ @@ -1306,7 +1322,7 @@ public final EnumType enumType() { * return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from * {@link #enumTypeAsString}. *

- * + * * @return The value of the EnumType property for this object. * @see EnumType */ @@ -1316,7 +1332,7 @@ public final String enumTypeAsString() { /** * Returns the value of the Underscore_Name_Type property for this object. - * + * * @return The value of the Underscore_Name_Type property for this object. */ public final Underscore_Name_Type underscore_Name_Type() { @@ -1325,7 +1341,7 @@ public final Underscore_Name_Type underscore_Name_Type() { /** * Returns the value of the MyDocument property for this object. - * + * * @return The value of the MyDocument property for this object. */ public final Document myDocument() { @@ -1334,7 +1350,7 @@ public final Document myDocument() { /** * Returns the value of the AllTypesUnionStructure property for this object. - * + * * @return The value of the AllTypesUnionStructure property for this object. */ public final AllTypesUnionStructure allTypesUnionStructure() { @@ -1365,6 +1381,7 @@ public final int hashCode() { hashCode = 31 * hashCode + Objects.hashCode(doubleMember()); hashCode = 31 * hashCode + Objects.hashCode(longMember()); hashCode = 31 * hashCode + Objects.hashCode(shortMember()); + hashCode = 31 * hashCode + Objects.hashCode(byteMember()); hashCode = 31 * hashCode + Objects.hashCode(hasSimpleList() ? simpleList() : null); hashCode = 31 * hashCode + Objects.hashCode(hasListOfEnums() ? listOfEnumsAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(hasListOfMaps() ? listOfMaps() : null); @@ -1380,7 +1397,7 @@ public final int hashCode() { hashCode = 31 * hashCode + Objects.hashCode(hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null); hashCode = 31 * hashCode - + Objects.hashCode(hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null); + + Objects.hashCode(hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null); hashCode = 31 * hashCode + Objects.hashCode(timestampMember()); hashCode = 31 * hashCode + Objects.hashCode(structWithNestedTimestampMember()); hashCode = 31 * hashCode + Objects.hashCode(blobArg()); @@ -1415,48 +1432,49 @@ public final boolean equalsBySdkFields(Object obj) { } AllTypesResponse other = (AllTypesResponse) obj; return Objects.equals(stringMember(), other.stringMember()) && Objects.equals(integerMember(), other.integerMember()) - && Objects.equals(booleanMember(), other.booleanMember()) && Objects.equals(floatMember(), other.floatMember()) - && Objects.equals(doubleMember(), other.doubleMember()) && Objects.equals(longMember(), other.longMember()) - && Objects.equals(shortMember(), other.shortMember()) && hasSimpleList() == other.hasSimpleList() - && Objects.equals(simpleList(), other.simpleList()) && hasListOfEnums() == other.hasListOfEnums() - && Objects.equals(listOfEnumsAsStrings(), other.listOfEnumsAsStrings()) - && hasListOfMaps() == other.hasListOfMaps() && Objects.equals(listOfMaps(), other.listOfMaps()) - && hasListOfStructs() == other.hasListOfStructs() && Objects.equals(listOfStructs(), other.listOfStructs()) - && hasListOfMapOfEnumToString() == other.hasListOfMapOfEnumToString() - && Objects.equals(listOfMapOfEnumToStringAsStrings(), other.listOfMapOfEnumToStringAsStrings()) - && hasListOfMapOfStringToStruct() == other.hasListOfMapOfStringToStruct() - && Objects.equals(listOfMapOfStringToStruct(), other.listOfMapOfStringToStruct()) - && hasMapOfStringToIntegerList() == other.hasMapOfStringToIntegerList() - && Objects.equals(mapOfStringToIntegerList(), other.mapOfStringToIntegerList()) - && hasMapOfStringToString() == other.hasMapOfStringToString() - && Objects.equals(mapOfStringToString(), other.mapOfStringToString()) - && hasMapOfStringToSimpleStruct() == other.hasMapOfStringToSimpleStruct() - && Objects.equals(mapOfStringToSimpleStruct(), other.mapOfStringToSimpleStruct()) - && hasMapOfEnumToEnum() == other.hasMapOfEnumToEnum() - && Objects.equals(mapOfEnumToEnumAsStrings(), other.mapOfEnumToEnumAsStrings()) - && hasMapOfEnumToString() == other.hasMapOfEnumToString() - && Objects.equals(mapOfEnumToStringAsStrings(), other.mapOfEnumToStringAsStrings()) - && hasMapOfStringToEnum() == other.hasMapOfStringToEnum() - && Objects.equals(mapOfStringToEnumAsStrings(), other.mapOfStringToEnumAsStrings()) - && hasMapOfEnumToSimpleStruct() == other.hasMapOfEnumToSimpleStruct() - && Objects.equals(mapOfEnumToSimpleStructAsStrings(), other.mapOfEnumToSimpleStructAsStrings()) - && hasMapOfEnumToListOfEnums() == other.hasMapOfEnumToListOfEnums() - && Objects.equals(mapOfEnumToListOfEnumsAsStrings(), other.mapOfEnumToListOfEnumsAsStrings()) - && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() - && Objects.equals(mapOfEnumToMapOfStringToEnumAsStrings(), other.mapOfEnumToMapOfStringToEnumAsStrings()) - && Objects.equals(timestampMember(), other.timestampMember()) - && Objects.equals(structWithNestedTimestampMember(), other.structWithNestedTimestampMember()) - && Objects.equals(blobArg(), other.blobArg()) - && Objects.equals(structWithNestedBlob(), other.structWithNestedBlob()) && hasBlobMap() == other.hasBlobMap() - && Objects.equals(blobMap(), other.blobMap()) && hasListOfBlobs() == other.hasListOfBlobs() - && Objects.equals(listOfBlobs(), other.listOfBlobs()) - && Objects.equals(recursiveStruct(), other.recursiveStruct()) - && Objects.equals(polymorphicTypeWithSubTypes(), other.polymorphicTypeWithSubTypes()) - && Objects.equals(polymorphicTypeWithoutSubTypes(), other.polymorphicTypeWithoutSubTypes()) - && Objects.equals(enumTypeAsString(), other.enumTypeAsString()) - && Objects.equals(underscore_Name_Type(), other.underscore_Name_Type()) - && Objects.equals(myDocument(), other.myDocument()) - && Objects.equals(allTypesUnionStructure(), other.allTypesUnionStructure()); + && Objects.equals(booleanMember(), other.booleanMember()) && Objects.equals(floatMember(), other.floatMember()) + && Objects.equals(doubleMember(), other.doubleMember()) && Objects.equals(longMember(), other.longMember()) + && Objects.equals(shortMember(), other.shortMember()) && Objects.equals(byteMember(), other.byteMember()) + && hasSimpleList() == other.hasSimpleList() && Objects.equals(simpleList(), other.simpleList()) + && hasListOfEnums() == other.hasListOfEnums() + && Objects.equals(listOfEnumsAsStrings(), other.listOfEnumsAsStrings()) + && hasListOfMaps() == other.hasListOfMaps() && Objects.equals(listOfMaps(), other.listOfMaps()) + && hasListOfStructs() == other.hasListOfStructs() && Objects.equals(listOfStructs(), other.listOfStructs()) + && hasListOfMapOfEnumToString() == other.hasListOfMapOfEnumToString() + && Objects.equals(listOfMapOfEnumToStringAsStrings(), other.listOfMapOfEnumToStringAsStrings()) + && hasListOfMapOfStringToStruct() == other.hasListOfMapOfStringToStruct() + && Objects.equals(listOfMapOfStringToStruct(), other.listOfMapOfStringToStruct()) + && hasMapOfStringToIntegerList() == other.hasMapOfStringToIntegerList() + && Objects.equals(mapOfStringToIntegerList(), other.mapOfStringToIntegerList()) + && hasMapOfStringToString() == other.hasMapOfStringToString() + && Objects.equals(mapOfStringToString(), other.mapOfStringToString()) + && hasMapOfStringToSimpleStruct() == other.hasMapOfStringToSimpleStruct() + && Objects.equals(mapOfStringToSimpleStruct(), other.mapOfStringToSimpleStruct()) + && hasMapOfEnumToEnum() == other.hasMapOfEnumToEnum() + && Objects.equals(mapOfEnumToEnumAsStrings(), other.mapOfEnumToEnumAsStrings()) + && hasMapOfEnumToString() == other.hasMapOfEnumToString() + && Objects.equals(mapOfEnumToStringAsStrings(), other.mapOfEnumToStringAsStrings()) + && hasMapOfStringToEnum() == other.hasMapOfStringToEnum() + && Objects.equals(mapOfStringToEnumAsStrings(), other.mapOfStringToEnumAsStrings()) + && hasMapOfEnumToSimpleStruct() == other.hasMapOfEnumToSimpleStruct() + && Objects.equals(mapOfEnumToSimpleStructAsStrings(), other.mapOfEnumToSimpleStructAsStrings()) + && hasMapOfEnumToListOfEnums() == other.hasMapOfEnumToListOfEnums() + && Objects.equals(mapOfEnumToListOfEnumsAsStrings(), other.mapOfEnumToListOfEnumsAsStrings()) + && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() + && Objects.equals(mapOfEnumToMapOfStringToEnumAsStrings(), other.mapOfEnumToMapOfStringToEnumAsStrings()) + && Objects.equals(timestampMember(), other.timestampMember()) + && Objects.equals(structWithNestedTimestampMember(), other.structWithNestedTimestampMember()) + && Objects.equals(blobArg(), other.blobArg()) + && Objects.equals(structWithNestedBlob(), other.structWithNestedBlob()) && hasBlobMap() == other.hasBlobMap() + && Objects.equals(blobMap(), other.blobMap()) && hasListOfBlobs() == other.hasListOfBlobs() + && Objects.equals(listOfBlobs(), other.listOfBlobs()) + && Objects.equals(recursiveStruct(), other.recursiveStruct()) + && Objects.equals(polymorphicTypeWithSubTypes(), other.polymorphicTypeWithSubTypes()) + && Objects.equals(polymorphicTypeWithoutSubTypes(), other.polymorphicTypeWithoutSubTypes()) + && Objects.equals(enumTypeAsString(), other.enumTypeAsString()) + && Objects.equals(underscore_Name_Type(), other.underscore_Name_Type()) + && Objects.equals(myDocument(), other.myDocument()) + && Objects.equals(allTypesUnionStructure(), other.allTypesUnionStructure()); } /** @@ -1466,114 +1484,117 @@ && hasMapOfEnumToMapOfStringToEnum() == other.hasMapOfEnumToMapOfStringToEnum() @Override public final String toString() { return ToString - .builder("AllTypesResponse") - .add("StringMember", stringMember()) - .add("IntegerMember", integerMember()) - .add("BooleanMember", booleanMember()) - .add("FloatMember", floatMember()) - .add("DoubleMember", doubleMember()) - .add("LongMember", longMember()) - .add("ShortMember", shortMember()) - .add("SimpleList", hasSimpleList() ? simpleList() : null) - .add("ListOfEnums", hasListOfEnums() ? listOfEnumsAsStrings() : null) - .add("ListOfMaps", hasListOfMaps() ? listOfMaps() : null) - .add("ListOfStructs", hasListOfStructs() ? listOfStructs() : null) - .add("ListOfMapOfEnumToString", hasListOfMapOfEnumToString() ? listOfMapOfEnumToStringAsStrings() : null) - .add("ListOfMapOfStringToStruct", hasListOfMapOfStringToStruct() ? listOfMapOfStringToStruct() : null) - .add("MapOfStringToIntegerList", hasMapOfStringToIntegerList() ? mapOfStringToIntegerList() : null) - .add("MapOfStringToString", hasMapOfStringToString() ? mapOfStringToString() : null) - .add("MapOfStringToSimpleStruct", hasMapOfStringToSimpleStruct() ? mapOfStringToSimpleStruct() : null) - .add("MapOfEnumToEnum", hasMapOfEnumToEnum() ? mapOfEnumToEnumAsStrings() : null) - .add("MapOfEnumToString", hasMapOfEnumToString() ? mapOfEnumToStringAsStrings() : null) - .add("MapOfStringToEnum", hasMapOfStringToEnum() ? mapOfStringToEnumAsStrings() : null) - .add("MapOfEnumToSimpleStruct", hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null) - .add("MapOfEnumToListOfEnums", hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null) - .add("MapOfEnumToMapOfStringToEnum", - hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null) - .add("TimestampMember", timestampMember()) - .add("StructWithNestedTimestampMember", structWithNestedTimestampMember()).add("BlobArg", blobArg()) - .add("StructWithNestedBlob", structWithNestedBlob()).add("BlobMap", hasBlobMap() ? blobMap() : null) - .add("ListOfBlobs", hasListOfBlobs() ? listOfBlobs() : null).add("RecursiveStruct", recursiveStruct()) - .add("PolymorphicTypeWithSubTypes", polymorphicTypeWithSubTypes()) - .add("PolymorphicTypeWithoutSubTypes", polymorphicTypeWithoutSubTypes()).add("EnumType", enumTypeAsString()) - .add("Underscore_Name_Type", underscore_Name_Type()).add("MyDocument", myDocument()) - .add("AllTypesUnionStructure", allTypesUnionStructure()).build(); + .builder("AllTypesResponse") + .add("StringMember", stringMember()) + .add("IntegerMember", integerMember()) + .add("BooleanMember", booleanMember()) + .add("FloatMember", floatMember()) + .add("DoubleMember", doubleMember()) + .add("LongMember", longMember()) + .add("ShortMember", shortMember()) + .add("ByteMember", byteMember()) + .add("SimpleList", hasSimpleList() ? simpleList() : null) + .add("ListOfEnums", hasListOfEnums() ? listOfEnumsAsStrings() : null) + .add("ListOfMaps", hasListOfMaps() ? listOfMaps() : null) + .add("ListOfStructs", hasListOfStructs() ? listOfStructs() : null) + .add("ListOfMapOfEnumToString", hasListOfMapOfEnumToString() ? listOfMapOfEnumToStringAsStrings() : null) + .add("ListOfMapOfStringToStruct", hasListOfMapOfStringToStruct() ? listOfMapOfStringToStruct() : null) + .add("MapOfStringToIntegerList", hasMapOfStringToIntegerList() ? mapOfStringToIntegerList() : null) + .add("MapOfStringToString", hasMapOfStringToString() ? mapOfStringToString() : null) + .add("MapOfStringToSimpleStruct", hasMapOfStringToSimpleStruct() ? mapOfStringToSimpleStruct() : null) + .add("MapOfEnumToEnum", hasMapOfEnumToEnum() ? mapOfEnumToEnumAsStrings() : null) + .add("MapOfEnumToString", hasMapOfEnumToString() ? mapOfEnumToStringAsStrings() : null) + .add("MapOfStringToEnum", hasMapOfStringToEnum() ? mapOfStringToEnumAsStrings() : null) + .add("MapOfEnumToSimpleStruct", hasMapOfEnumToSimpleStruct() ? mapOfEnumToSimpleStructAsStrings() : null) + .add("MapOfEnumToListOfEnums", hasMapOfEnumToListOfEnums() ? mapOfEnumToListOfEnumsAsStrings() : null) + .add("MapOfEnumToMapOfStringToEnum", + hasMapOfEnumToMapOfStringToEnum() ? mapOfEnumToMapOfStringToEnumAsStrings() : null) + .add("TimestampMember", timestampMember()) + .add("StructWithNestedTimestampMember", structWithNestedTimestampMember()).add("BlobArg", blobArg()) + .add("StructWithNestedBlob", structWithNestedBlob()).add("BlobMap", hasBlobMap() ? blobMap() : null) + .add("ListOfBlobs", hasListOfBlobs() ? listOfBlobs() : null).add("RecursiveStruct", recursiveStruct()) + .add("PolymorphicTypeWithSubTypes", polymorphicTypeWithSubTypes()) + .add("PolymorphicTypeWithoutSubTypes", polymorphicTypeWithoutSubTypes()).add("EnumType", enumTypeAsString()) + .add("Underscore_Name_Type", underscore_Name_Type()).add("MyDocument", myDocument()) + .add("AllTypesUnionStructure", allTypesUnionStructure()).build(); } public final Optional getValueForField(String fieldName, Class clazz) { switch (fieldName) { - case "StringMember": - return Optional.ofNullable(clazz.cast(stringMember())); - case "IntegerMember": - return Optional.ofNullable(clazz.cast(integerMember())); - case "BooleanMember": - return Optional.ofNullable(clazz.cast(booleanMember())); - case "FloatMember": - return Optional.ofNullable(clazz.cast(floatMember())); - case "DoubleMember": - return Optional.ofNullable(clazz.cast(doubleMember())); - case "LongMember": - return Optional.ofNullable(clazz.cast(longMember())); - case "ShortMember": - return Optional.ofNullable(clazz.cast(shortMember())); - case "SimpleList": - return Optional.ofNullable(clazz.cast(simpleList())); - case "ListOfEnums": - return Optional.ofNullable(clazz.cast(listOfEnumsAsStrings())); - case "ListOfMaps": - return Optional.ofNullable(clazz.cast(listOfMaps())); - case "ListOfStructs": - return Optional.ofNullable(clazz.cast(listOfStructs())); - case "ListOfMapOfEnumToString": - return Optional.ofNullable(clazz.cast(listOfMapOfEnumToStringAsStrings())); - case "ListOfMapOfStringToStruct": - return Optional.ofNullable(clazz.cast(listOfMapOfStringToStruct())); - case "MapOfStringToIntegerList": - return Optional.ofNullable(clazz.cast(mapOfStringToIntegerList())); - case "MapOfStringToString": - return Optional.ofNullable(clazz.cast(mapOfStringToString())); - case "MapOfStringToSimpleStruct": - return Optional.ofNullable(clazz.cast(mapOfStringToSimpleStruct())); - case "MapOfEnumToEnum": - return Optional.ofNullable(clazz.cast(mapOfEnumToEnumAsStrings())); - case "MapOfEnumToString": - return Optional.ofNullable(clazz.cast(mapOfEnumToStringAsStrings())); - case "MapOfStringToEnum": - return Optional.ofNullable(clazz.cast(mapOfStringToEnumAsStrings())); - case "MapOfEnumToSimpleStruct": - return Optional.ofNullable(clazz.cast(mapOfEnumToSimpleStructAsStrings())); - case "MapOfEnumToListOfEnums": - return Optional.ofNullable(clazz.cast(mapOfEnumToListOfEnumsAsStrings())); - case "MapOfEnumToMapOfStringToEnum": - return Optional.ofNullable(clazz.cast(mapOfEnumToMapOfStringToEnumAsStrings())); - case "TimestampMember": - return Optional.ofNullable(clazz.cast(timestampMember())); - case "StructWithNestedTimestampMember": - return Optional.ofNullable(clazz.cast(structWithNestedTimestampMember())); - case "BlobArg": - return Optional.ofNullable(clazz.cast(blobArg())); - case "StructWithNestedBlob": - return Optional.ofNullable(clazz.cast(structWithNestedBlob())); - case "BlobMap": - return Optional.ofNullable(clazz.cast(blobMap())); - case "ListOfBlobs": - return Optional.ofNullable(clazz.cast(listOfBlobs())); - case "RecursiveStruct": - return Optional.ofNullable(clazz.cast(recursiveStruct())); - case "PolymorphicTypeWithSubTypes": - return Optional.ofNullable(clazz.cast(polymorphicTypeWithSubTypes())); - case "PolymorphicTypeWithoutSubTypes": - return Optional.ofNullable(clazz.cast(polymorphicTypeWithoutSubTypes())); - case "EnumType": - return Optional.ofNullable(clazz.cast(enumTypeAsString())); - case "Underscore_Name_Type": - return Optional.ofNullable(clazz.cast(underscore_Name_Type())); - case "MyDocument": - return Optional.ofNullable(clazz.cast(myDocument())); - case "AllTypesUnionStructure": - return Optional.ofNullable(clazz.cast(allTypesUnionStructure())); - default: - return Optional.empty(); + case "StringMember": + return Optional.ofNullable(clazz.cast(stringMember())); + case "IntegerMember": + return Optional.ofNullable(clazz.cast(integerMember())); + case "BooleanMember": + return Optional.ofNullable(clazz.cast(booleanMember())); + case "FloatMember": + return Optional.ofNullable(clazz.cast(floatMember())); + case "DoubleMember": + return Optional.ofNullable(clazz.cast(doubleMember())); + case "LongMember": + return Optional.ofNullable(clazz.cast(longMember())); + case "ShortMember": + return Optional.ofNullable(clazz.cast(shortMember())); + case "ByteMember": + return Optional.ofNullable(clazz.cast(byteMember())); + case "SimpleList": + return Optional.ofNullable(clazz.cast(simpleList())); + case "ListOfEnums": + return Optional.ofNullable(clazz.cast(listOfEnumsAsStrings())); + case "ListOfMaps": + return Optional.ofNullable(clazz.cast(listOfMaps())); + case "ListOfStructs": + return Optional.ofNullable(clazz.cast(listOfStructs())); + case "ListOfMapOfEnumToString": + return Optional.ofNullable(clazz.cast(listOfMapOfEnumToStringAsStrings())); + case "ListOfMapOfStringToStruct": + return Optional.ofNullable(clazz.cast(listOfMapOfStringToStruct())); + case "MapOfStringToIntegerList": + return Optional.ofNullable(clazz.cast(mapOfStringToIntegerList())); + case "MapOfStringToString": + return Optional.ofNullable(clazz.cast(mapOfStringToString())); + case "MapOfStringToSimpleStruct": + return Optional.ofNullable(clazz.cast(mapOfStringToSimpleStruct())); + case "MapOfEnumToEnum": + return Optional.ofNullable(clazz.cast(mapOfEnumToEnumAsStrings())); + case "MapOfEnumToString": + return Optional.ofNullable(clazz.cast(mapOfEnumToStringAsStrings())); + case "MapOfStringToEnum": + return Optional.ofNullable(clazz.cast(mapOfStringToEnumAsStrings())); + case "MapOfEnumToSimpleStruct": + return Optional.ofNullable(clazz.cast(mapOfEnumToSimpleStructAsStrings())); + case "MapOfEnumToListOfEnums": + return Optional.ofNullable(clazz.cast(mapOfEnumToListOfEnumsAsStrings())); + case "MapOfEnumToMapOfStringToEnum": + return Optional.ofNullable(clazz.cast(mapOfEnumToMapOfStringToEnumAsStrings())); + case "TimestampMember": + return Optional.ofNullable(clazz.cast(timestampMember())); + case "StructWithNestedTimestampMember": + return Optional.ofNullable(clazz.cast(structWithNestedTimestampMember())); + case "BlobArg": + return Optional.ofNullable(clazz.cast(blobArg())); + case "StructWithNestedBlob": + return Optional.ofNullable(clazz.cast(structWithNestedBlob())); + case "BlobMap": + return Optional.ofNullable(clazz.cast(blobMap())); + case "ListOfBlobs": + return Optional.ofNullable(clazz.cast(listOfBlobs())); + case "RecursiveStruct": + return Optional.ofNullable(clazz.cast(recursiveStruct())); + case "PolymorphicTypeWithSubTypes": + return Optional.ofNullable(clazz.cast(polymorphicTypeWithSubTypes())); + case "PolymorphicTypeWithoutSubTypes": + return Optional.ofNullable(clazz.cast(polymorphicTypeWithoutSubTypes())); + case "EnumType": + return Optional.ofNullable(clazz.cast(enumTypeAsString())); + case "Underscore_Name_Type": + return Optional.ofNullable(clazz.cast(underscore_Name_Type())); + case "MyDocument": + return Optional.ofNullable(clazz.cast(myDocument())); + case "AllTypesUnionStructure": + return Optional.ofNullable(clazz.cast(allTypesUnionStructure())); + default: + return Optional.empty(); } } @@ -1654,6 +1675,15 @@ public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, Cop */ Builder shortMember(Short shortMember); + /** + * Sets the value of the ByteMember property for this object. + * + * @param byteMember + * The new value for the ByteMember property for this object. + * @return Returns a reference to this object so that method calls can be chained together. + */ + Builder byteMember(Byte byteMember); + /** * Sets the value of the SimpleList property for this object. * @@ -1756,7 +1786,7 @@ public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, Cop * When the {@link Consumer} completes, * {@link software.amazon.awssdk.services.jsonprotocoltests.model.SimpleStruct.Builder#build()} is called * immediately and its result is passed to {@link #listOfStructs(List)}. - * + * * @param listOfStructs * a consumer that will call methods on * {@link software.amazon.awssdk.services.jsonprotocoltests.model.SimpleStruct.Builder} @@ -1963,7 +1993,7 @@ public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, Cop *

* When the {@link Consumer} completes, {@link StructWithTimestamp.Builder#build()} is called immediately and * its result is passed to {@link #structWithNestedTimestampMember(StructWithTimestamp)}. - * + * * @param structWithNestedTimestampMember * a consumer that will call methods on {@link StructWithTimestamp.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -1971,7 +2001,7 @@ public interface Builder extends JsonProtocolTestsResponse.Builder, SdkPojo, Cop */ default Builder structWithNestedTimestampMember(Consumer structWithNestedTimestampMember) { return structWithNestedTimestampMember(StructWithTimestamp.builder().applyMutation(structWithNestedTimestampMember) - .build()); + .build()); } /** @@ -2001,7 +2031,7 @@ default Builder structWithNestedTimestampMember(Consumer * When the {@link Consumer} completes, {@link StructWithNestedBlobType.Builder#build()} is called immediately * and its result is passed to {@link #structWithNestedBlob(StructWithNestedBlobType)}. - * + * * @param structWithNestedBlob * a consumer that will call methods on {@link StructWithNestedBlobType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2056,7 +2086,7 @@ default Builder structWithNestedBlob(Consumer *

* When the {@link Consumer} completes, {@link RecursiveStructType.Builder#build()} is called immediately and * its result is passed to {@link #recursiveStruct(RecursiveStructType)}. - * + * * @param recursiveStruct * a consumer that will call methods on {@link RecursiveStructType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2084,7 +2114,7 @@ default Builder recursiveStruct(Consumer recursiveS *

* When the {@link Consumer} completes, {@link BaseType.Builder#build()} is called immediately and its result is * passed to {@link #polymorphicTypeWithSubTypes(BaseType)}. - * + * * @param polymorphicTypeWithSubTypes * a consumer that will call methods on {@link BaseType.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2112,7 +2142,7 @@ default Builder polymorphicTypeWithSubTypes(Consumer polymorph *

* When the {@link Consumer} completes, {@link SubTypeOne.Builder#build()} is called immediately and its result * is passed to {@link #polymorphicTypeWithoutSubTypes(SubTypeOne)}. - * + * * @param polymorphicTypeWithoutSubTypes * a consumer that will call methods on {@link SubTypeOne.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2162,7 +2192,7 @@ default Builder polymorphicTypeWithoutSubTypes(Consumer poly *

* When the {@link Consumer} completes, {@link Underscore_Name_Type.Builder#build()} is called immediately and * its result is passed to {@link #underscore_Name_Type(Underscore_Name_Type)}. - * + * * @param underscore_Name_Type * a consumer that will call methods on {@link Underscore_Name_Type.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2199,7 +2229,7 @@ default Builder underscore_Name_Type(Consumer unde *

* When the {@link Consumer} completes, {@link AllTypesUnionStructure.Builder#build()} is called immediately and * its result is passed to {@link #allTypesUnionStructure(AllTypesUnionStructure)}. - * + * * @param allTypesUnionStructure * a consumer that will call methods on {@link AllTypesUnionStructure.Builder} * @return Returns a reference to this object so that method calls can be chained together. @@ -2225,6 +2255,8 @@ static final class BuilderImpl extends JsonProtocolTestsResponse.BuilderImpl imp private Short shortMember; + private Byte byteMember; + private List simpleList = DefaultSdkAutoConstructList.getInstance(); private List listOfEnums = DefaultSdkAutoConstructList.getInstance(); @@ -2293,6 +2325,7 @@ private BuilderImpl(AllTypesResponse model) { doubleMember(model.doubleMember); longMember(model.longMember); shortMember(model.shortMember); + byteMember(model.byteMember); simpleList(model.simpleList); listOfEnumsWithStrings(model.listOfEnums); listOfMaps(model.listOfMaps); @@ -2421,6 +2454,20 @@ public final Builder shortMember(Short shortMember) { return this; } + public final Byte getByteMember() { + return byteMember; + } + + public final void setByteMember(Byte byteMember) { + this.byteMember = byteMember; + } + + @Override + public final Builder byteMember(Byte byteMember) { + this.byteMember = byteMember; + return this; + } + public final Collection getSimpleList() { if (simpleList instanceof SdkAutoConstructList) { return null; @@ -2535,7 +2582,7 @@ public final Builder listOfStructs(SimpleStruct... listOfStructs) { @SafeVarargs public final Builder listOfStructs(Consumer... listOfStructs) { listOfStructs(Stream.of(listOfStructs).map(c -> SimpleStruct.builder().applyMutation(c).build()) - .collect(Collectors.toList())); + .collect(Collectors.toList())); return this; } @@ -2565,7 +2612,7 @@ public final Builder listOfMapOfEnumToStringWithStrings(Map... l public final List> getListOfMapOfStringToStruct() { List> result = ListOfMapOfStringToStructCopier - .copyToBuilder(this.listOfMapOfStringToStruct); + .copyToBuilder(this.listOfMapOfStringToStruct); if (result instanceof SdkAutoConstructList) { return null; } @@ -2573,7 +2620,7 @@ public final List> getListOfMapOfStringToStruc } public final void setListOfMapOfStringToStruct( - Collection> listOfMapOfStringToStruct) { + Collection> listOfMapOfStringToStruct) { this.listOfMapOfStringToStruct = ListOfMapOfStringToStructCopier.copyFromBuilder(listOfMapOfStringToStruct); } @@ -2626,7 +2673,7 @@ public final Builder mapOfStringToString(Map mapOfStringToString public final Map getMapOfStringToSimpleStruct() { Map result = MapOfStringToSimpleStructCopier - .copyToBuilder(this.mapOfStringToSimpleStruct); + .copyToBuilder(this.mapOfStringToSimpleStruct); if (result instanceof SdkAutoConstructMap) { return null; } @@ -2772,14 +2819,14 @@ public final void setMapOfEnumToMapOfStringToEnum(Map> mapOfEnumToMapOfStringToEnum) { + Map> mapOfEnumToMapOfStringToEnum) { this.mapOfEnumToMapOfStringToEnum = MapOfEnumToMapOfStringToEnumCopier.copy(mapOfEnumToMapOfStringToEnum); return this; } @Override public final Builder mapOfEnumToMapOfStringToEnum( - Map> mapOfEnumToMapOfStringToEnum) { + Map> mapOfEnumToMapOfStringToEnum) { this.mapOfEnumToMapOfStringToEnum = MapOfEnumToMapOfStringToEnumCopier.copyEnumToString(mapOfEnumToMapOfStringToEnum); return this; } @@ -2804,7 +2851,7 @@ public final StructWithTimestamp.Builder getStructWithNestedTimestampMember() { public final void setStructWithNestedTimestampMember(StructWithTimestamp.BuilderImpl structWithNestedTimestampMember) { this.structWithNestedTimestampMember = structWithNestedTimestampMember != null ? structWithNestedTimestampMember - .build() : null; + .build() : null; } @Override @@ -2846,12 +2893,12 @@ public final Map getBlobMap() { return null; } return blobMap == null ? null : blobMap.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().asByteBuffer())); + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().asByteBuffer())); } public final void setBlobMap(Map blobMap) { blobMap(blobMap == null ? null : blobMap.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> SdkBytes.fromByteBuffer(e.getValue())))); + .collect(Collectors.toMap(e -> e.getKey(), e -> SdkBytes.fromByteBuffer(e.getValue())))); } @Override @@ -2869,7 +2916,7 @@ public final List getListOfBlobs() { public final void setListOfBlobs(Collection listOfBlobs) { listOfBlobs(listOfBlobs == null ? null : listOfBlobs.stream().map(SdkBytes::fromByteBuffer) - .collect(Collectors.toList())); + .collect(Collectors.toList())); } @Override @@ -2919,7 +2966,7 @@ public final SubTypeOne.Builder getPolymorphicTypeWithoutSubTypes() { public final void setPolymorphicTypeWithoutSubTypes(SubTypeOne.BuilderImpl polymorphicTypeWithoutSubTypes) { this.polymorphicTypeWithoutSubTypes = polymorphicTypeWithoutSubTypes != null ? polymorphicTypeWithoutSubTypes.build() - : null; + : null; } @Override 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 e846f69f04ed..6823581873a8 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 @@ -1,3 +1,4 @@ + { "version":"2.0", "metadata":{ @@ -140,6 +141,7 @@ "DoubleMember":{"shape":"Double"}, "LongMember":{"shape":"Long"}, "ShortMember":{"shape":"Short"}, + "ByteMember":{"shape":"Byte"}, "SimpleList":{"shape":"ListOfStrings"}, "ListOfEnums":{"shape":"ListOfEnums"}, "ListOfMaps":{"shape":"ListOfMapStringToString"}, @@ -341,6 +343,7 @@ }, "Long":{"type":"long"}, "Short":{"type":"short"}, + "Byte":{"type":"byte"}, "MapOfStringToIntegerList":{ "type":"map", "key":{"shape":"String"}, diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/SdkJsonGenerator.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/SdkJsonGenerator.java index 228333bdf724..bfd819708b33 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/SdkJsonGenerator.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/SdkJsonGenerator.java @@ -166,6 +166,16 @@ public StructuredJsonGenerator writeValue(float val) { return this; } + @Override + public StructuredJsonGenerator writeValue(byte val) { + try { + generator.writeNumber(val); + } catch (IOException e) { + throw new JsonGenerationException(e); + } + return this; + } + @Override public StructuredJsonGenerator writeValue(short val) { try { diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java index 98b83699849c..5d84ed0a9906 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java @@ -157,6 +157,10 @@ public String getContentType() { StructuredJsonGenerator writeValue(short val); + default StructuredJsonGenerator writeValue(byte val) { + return writeValue((short) val); + } + StructuredJsonGenerator writeValue(int val); StructuredJsonGenerator writeValue(ByteBuffer bytes); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java index a3e3114a1628..110cdf36a11b 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java @@ -44,6 +44,8 @@ public final class HeaderMarshaller { public static final JsonMarshaller SHORT = new SimpleHeaderMarshaller<>(ValueToStringConverter.FROM_SHORT); + public static final JsonMarshaller BYTE = new SimpleHeaderMarshaller<>(ValueToStringConverter.FROM_BYTE); + public static final JsonMarshaller DOUBLE = new SimpleHeaderMarshaller<>(ValueToStringConverter.FROM_DOUBLE); public static final JsonMarshaller FLOAT = new SimpleHeaderMarshaller<>(ValueToStringConverter.FROM_FLOAT); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java index 92f34920d2c8..c0a3f46bff05 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java @@ -100,6 +100,7 @@ private static JsonMarshallerRegistry createMarshallerRegistry() { .payloadMarshaller(MarshallingType.INTEGER, SimpleTypeJsonMarshaller.INTEGER) .payloadMarshaller(MarshallingType.LONG, SimpleTypeJsonMarshaller.LONG) .payloadMarshaller(MarshallingType.SHORT, SimpleTypeJsonMarshaller.SHORT) + .payloadMarshaller(MarshallingType.BYTE, SimpleTypeJsonMarshaller.BYTE) .payloadMarshaller(MarshallingType.DOUBLE, SimpleTypeJsonMarshaller.DOUBLE) .payloadMarshaller(MarshallingType.FLOAT, SimpleTypeJsonMarshaller.FLOAT) .payloadMarshaller(MarshallingType.BIG_DECIMAL, SimpleTypeJsonMarshaller.BIG_DECIMAL) @@ -116,6 +117,7 @@ private static JsonMarshallerRegistry createMarshallerRegistry() { .headerMarshaller(MarshallingType.INTEGER, HeaderMarshaller.INTEGER) .headerMarshaller(MarshallingType.LONG, HeaderMarshaller.LONG) .headerMarshaller(MarshallingType.SHORT, HeaderMarshaller.SHORT) + .headerMarshaller(MarshallingType.BYTE, HeaderMarshaller.BYTE) .headerMarshaller(MarshallingType.DOUBLE, HeaderMarshaller.DOUBLE) .headerMarshaller(MarshallingType.FLOAT, HeaderMarshaller.FLOAT) .headerMarshaller(MarshallingType.BOOLEAN, HeaderMarshaller.BOOLEAN) @@ -127,6 +129,7 @@ private static JsonMarshallerRegistry createMarshallerRegistry() { .queryParamMarshaller(MarshallingType.INTEGER, QueryParamMarshaller.INTEGER) .queryParamMarshaller(MarshallingType.LONG, QueryParamMarshaller.LONG) .queryParamMarshaller(MarshallingType.SHORT, QueryParamMarshaller.SHORT) + .queryParamMarshaller(MarshallingType.BYTE, QueryParamMarshaller.BYTE) .queryParamMarshaller(MarshallingType.DOUBLE, QueryParamMarshaller.DOUBLE) .queryParamMarshaller(MarshallingType.FLOAT, QueryParamMarshaller.FLOAT) .queryParamMarshaller(MarshallingType.BOOLEAN, QueryParamMarshaller.BOOLEAN) @@ -139,6 +142,7 @@ private static JsonMarshallerRegistry createMarshallerRegistry() { .pathParamMarshaller(MarshallingType.INTEGER, SimpleTypePathMarshaller.INTEGER) .pathParamMarshaller(MarshallingType.LONG, SimpleTypePathMarshaller.LONG) .pathParamMarshaller(MarshallingType.SHORT, SimpleTypePathMarshaller.SHORT) + .pathParamMarshaller(MarshallingType.BYTE, SimpleTypePathMarshaller.BYTE) .pathParamMarshaller(MarshallingType.NULL, SimpleTypePathMarshaller.NULL) .greedyPathParamMarshaller(MarshallingType.STRING, SimpleTypePathMarshaller.GREEDY_STRING) diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java index f2cb143d57b0..e6445670ab2a 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java @@ -38,6 +38,8 @@ public final class QueryParamMarshaller { public static final JsonMarshaller SHORT = new SimpleQueryParamMarshaller<>(ValueToStringConverter.FROM_SHORT); + public static final JsonMarshaller BYTE = new SimpleQueryParamMarshaller<>(ValueToStringConverter.FROM_BYTE); + public static final JsonMarshaller DOUBLE = new SimpleQueryParamMarshaller<>( ValueToStringConverter.FROM_DOUBLE); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java index d9979f84042a..a1eb5a77d4f3 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java @@ -82,6 +82,13 @@ public void marshall(Short val, StructuredJsonGenerator jsonGenerator, JsonMarsh } }; + public static final JsonMarshaller BYTE = new BaseJsonMarshaller() { + @Override + public void marshall(Byte val, StructuredJsonGenerator jsonGenerator, JsonMarshallerContext context) { + jsonGenerator.writeValue(val); + } + }; + public static final JsonMarshaller FLOAT = new BaseJsonMarshaller() { @Override public void marshall(Float val, StructuredJsonGenerator jsonGenerator, JsonMarshallerContext context) { diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypePathMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypePathMarshaller.java index d653788a37ae..b2cc279b3f08 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypePathMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypePathMarshaller.java @@ -35,6 +35,9 @@ public final class SimpleTypePathMarshaller { public static final JsonMarshaller SHORT = new SimplePathMarshaller<>(ValueToStringConverter.FROM_SHORT, PathMarshaller.NON_GREEDY); + public static final JsonMarshaller BYTE = + new SimplePathMarshaller<>(ValueToStringConverter.FROM_BYTE, PathMarshaller.NON_GREEDY); + /** * Marshallers for Strings bound to a greedy path param. No URL encoding is done on the string * so that it preserves the path structure. diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java index f067a8fbcd6f..e55a75797c91 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java @@ -88,6 +88,7 @@ private static JsonUnmarshallerRegistry createUnmarshallerRegistry( .payloadUnmarshaller(MarshallingType.STRING, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_STRING)) .payloadUnmarshaller(MarshallingType.INTEGER, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_INTEGER)) .payloadUnmarshaller(MarshallingType.LONG, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_LONG)) + .payloadUnmarshaller(MarshallingType.BYTE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_BYTE)) .payloadUnmarshaller(MarshallingType.SHORT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_SHORT)) .payloadUnmarshaller(MarshallingType.FLOAT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_FLOAT)) .payloadUnmarshaller(MarshallingType.DOUBLE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_DOUBLE)) diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToValueConverter.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToValueConverter.java index 251456f50d5f..2a3a58aaea95 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToValueConverter.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToValueConverter.java @@ -76,6 +76,8 @@ default T convert(String s, SdkField sdkField) { public static final SimpleStringToValue TO_LONG = Long::parseLong; + public static final SimpleStringToValue TO_BYTE = Byte::parseByte; + public static final SimpleStringToValue TO_SHORT = Short::parseShort; public static final SimpleStringToValue TO_FLOAT = Float::parseFloat; diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/ValueToStringConverter.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/ValueToStringConverter.java index 508fbf618452..778b4016c920 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/ValueToStringConverter.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/ValueToStringConverter.java @@ -78,6 +78,8 @@ default String convert(T t, SdkField field) { public static final SimpleValueToString FROM_SHORT = Object::toString; + public static final SimpleValueToString FROM_BYTE = Object::toString; + public static final SimpleValueToString FROM_FLOAT = Object::toString; public static final SimpleValueToString FROM_DOUBLE = Object::toString; diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java index 8668b18a3814..ee345d6e8619 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java @@ -63,6 +63,8 @@ public interface MarshallingType { MarshallingType SHORT = newType(Short.class); + MarshallingType BYTE = newType(Byte.class); + MarshallingType DOCUMENT = newType(Document.class); Class getTargetClass(); diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java index 9e503bf1c65f..377f7b4e0863 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java @@ -230,7 +230,9 @@ private Object getSimpleMemberValue(JsonNode currentNode, MemberModel memberMode case "Long": return currentNode.asLong(); case "Short": - return (short) currentNode.asInt(); + return (short) currentNode.asInt(); + case "Byte": + return (byte) currentNode.asInt(); case "Integer": return currentNode.asInt(); case "String": diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-input.json index b1815aa8ba66..032f77b856a8 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-input.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-input.json @@ -10,7 +10,8 @@ "DoubleMember": 5.678, "BigDecimalMember": 1177.61699999, "LongMember": 2147483647, - "ShortMember": 5 + "ShortMember": 5, + "ByteMember": 127 } }, "when": { @@ -20,7 +21,7 @@ "then": { "serializedAs": { "body": { - "jsonEquals": "{\"StringMember\":\"someVal\",\"IntegerMember\":42,\"FloatMember\":1.234,\"DoubleMember\":5.678,\"BigDecimalMember\":\"1177.61699999\",\"LongMember\":2147483647,\"ShortMember\":5}" + "jsonEquals": "{\"StringMember\":\"someVal\",\"IntegerMember\":42,\"FloatMember\":1.234,\"DoubleMember\":5.678,\"BigDecimalMember\":\"1177.61699999\",\"LongMember\":2147483647,\"ShortMember\":5,\"ByteMember\": 127}" } } } diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-output.json index 807cde16ac3b..e1710a6b6f34 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-output.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json-core-output.json @@ -5,7 +5,7 @@ "given": { "response": { "status_code": 200, - "body": "{\"StringMember\": \"myname\", \"IntegerMember\": 123, \"FloatMember\": 1.2, \"DoubleMember\": 1.3, \"LongMember\": 200,\"BigDecimalMember\":1177.61699999, \"ShortMember\":5}" + "body": "{\"StringMember\": \"myname\", \"IntegerMember\": 123, \"FloatMember\": 1.2, \"DoubleMember\": 1.3, \"LongMember\": 200,\"BigDecimalMember\":1177.61699999, \"ShortMember\":5, \"ByteMember\":127}" } }, "when": { @@ -20,7 +20,8 @@ "DoubleMember": 1.3, "LongMember": 200, "BigDecimalMember": 1177.61699999, - "ShortMember": 5 + "ShortMember": 5, + "ByteMember": 127 } } }, diff --git a/test/protocol-tests/src/main/resources/codegen-resources/awsjson/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/awsjson/service-2.json index 340dd2caa73b..804153e63e1c 100644 --- a/test/protocol-tests/src/main/resources/codegen-resources/awsjson/service-2.json +++ b/test/protocol-tests/src/main/resources/codegen-resources/awsjson/service-2.json @@ -73,6 +73,7 @@ "BigDecimalMember":{"shape":"NumericValue"}, "LongMember":{"shape":"Long"}, "ShortMember":{"shape":"Short"}, + "ByteMember":{"shape":"Byte"}, "SimpleList":{"shape":"ListOfStrings"}, "ListOfMaps":{"shape":"ListOfMapStringToString"}, "ListOfStructs":{"shape":"ListOfSimpleStructs"}, @@ -127,6 +128,7 @@ }, "Float":{"type":"float"}, "Short":{"type":"short"}, + "Byte":{"type":"byte"}, "FurtherNestedContainersStructure":{ "type":"structure", "members":{ 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 d43d40a565eb..144f38b9a771 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 @@ -259,6 +259,7 @@ "DoubleMember":{"shape":"Double"}, "LongMember":{"shape":"Long"}, "ShortMember":{"shape":"Short"}, + "ByteMember":{"shape":"Byte"}, "BigDecimalMember":{"shape":"NumericValue"}, "SimpleList":{"shape":"ListOfStrings"}, "ListOfMaps":{"shape":"ListOfMapStringToString"}, @@ -494,6 +495,7 @@ }, "Long":{"type":"long"}, "Short":{"type":"short"}, + "Byte":{"type":"byte"}, "MapOfEnumToEnum":{ "type":"map", "key":{"shape":"EnumType"}, From 8b4378245f36bc7a5babace8d4837a08e1fe0051 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Thu, 15 Aug 2024 13:48:14 -0700 Subject: [PATCH 06/14] Add rpcv2 protocol core (#5496) * Add support to serialize byte values * Add RPCv2 protocol core marshalling/unmarshalling * Address PR comments * Address PR comments 2 * Address PR comments 3 --- codegen/pom.xml | 2 - .../DefaultCustomizationProcessor.java | 1 + .../SmithyRpcV2CborProtocolProcessor.java | 53 ++ .../amazon/awssdk/codegen/internal/Utils.java | 15 +- .../codegen/model/intermediate/Metadata.java | 12 +- .../codegen/model/intermediate/Protocol.java | 3 +- .../model/intermediate/ShapeMarshaller.java | 15 + .../codegen/poet/client/SyncClientClass.java | 1 + .../poet/client/specs/JsonProtocolSpec.java | 3 + .../poet/transform/MarshallerSpec.java | 1 + .../protocols/JsonMarshallerSpec.java | 8 + .../awscore/internal/AwsServiceProtocol.java | 1 + .../protocols/json/AwsJsonProtocol.java | 5 + .../json/BaseAwsJsonProtocolFactory.java | 5 +- .../json/StructuredJsonGenerator.java | 4 + .../marshall/JsonProtocolMarshaller.java | 21 +- .../marshall/SimpleTypeJsonMarshaller.java | 2 +- .../core/OperationMetadataAttribute.java | 6 + core/protocols/smithy-rpcv2-protocol/pom.xml | 2 - .../rpcv2/SmithyRpcV2CborProtocolFactory.java | 100 +++ .../rpcv2/internal/SdkRpcV2CborGenerator.java | 117 +++ .../SdkStructuredRpcV2CborFactory.java | 55 ++ .../internal/SdkRpcV2CborGeneratorTest.java | 217 ++++++ .../marshalling/EncodedBodyAssertion.java | 40 ++ .../marshalling/RequestBodyAssertion.java | 4 + .../awssdk/protocol/model/GivenResponse.java | 9 + .../runners/UnmarshallingTestRunner.java | 3 + .../suites/cases/smithy-rpcv2-input.json | 560 +++++++++++++++ .../suites/cases/smithy-rpcv2-output.json | 667 ++++++++++++++++++ .../protocol/suites/smithy-rpcv2-suite.json | 6 + test/protocol-tests/pom.xml | 2 - .../rpcv2/customization.config | 3 + .../rpcv2/endpoint-rule-set.json | 59 ++ .../rpcv2/endpoint-tests.json | 5 + .../codegen-resources/rpcv2/service-2.json | 546 ++++++++++++++ .../tests/SmithyRpcV2CborProtocolTest.java | 51 ++ 36 files changed, 2583 insertions(+), 21 deletions(-) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/SmithyRpcV2CborProtocolProcessor.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGenerator.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkStructuredRpcV2CborFactory.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/test/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGeneratorTest.java create mode 100644 test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/EncodedBodyAssertion.java create mode 100644 test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json create mode 100644 test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json create mode 100644 test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/smithy-rpcv2-suite.json create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/rpcv2/customization.config create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-rule-set.json create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-tests.json create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/rpcv2/service-2.json create mode 100644 test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/SmithyRpcV2CborProtocolTest.java diff --git a/codegen/pom.xml b/codegen/pom.xml index 0270787125c4..ffc2870fe13d 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -142,13 +142,11 @@ aws-xml-protocol ${awsjavasdk.version} - software.amazon.awssdk protocol-core diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java index d8a61167a7d8..bfdf58fc8045 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/DefaultCustomizationProcessor.java @@ -34,6 +34,7 @@ public static CodegenCustomizationProcessor getProcessorFor( new ShapeSubstitutionsProcessor(config.getShapeSubstitutions()), new CustomSdkShapesProcessor(config.getCustomSdkShapes()), new OperationModifiersProcessor(config.getOperationModifiers()), + new SmithyRpcV2CborProtocolProcessor(), new RemoveExceptionMessagePropertyProcessor(), new UseLegacyEventGenerationSchemeProcessor(), new NewAndLegacyEventStreamProcessor(), diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/SmithyRpcV2CborProtocolProcessor.java b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/SmithyRpcV2CborProtocolProcessor.java new file mode 100644 index 000000000000..d4921a6d4822 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/customization/processors/SmithyRpcV2CborProtocolProcessor.java @@ -0,0 +1,53 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.customization.processors; + +import software.amazon.awssdk.codegen.customization.CodegenCustomizationProcessor; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.service.Http; +import software.amazon.awssdk.codegen.model.service.Operation; +import software.amazon.awssdk.codegen.model.service.ServiceModel; +import software.amazon.awssdk.utils.StringUtils; + +/** + * This processor only runs for services using the smithy-rpc-v2-cbor protocol. + * + * Adds a request URI that conform to the Smithy RPCv2 protocol to each operation in the model, if there's no URI already + * defined. + */ +public class SmithyRpcV2CborProtocolProcessor implements CodegenCustomizationProcessor { + @Override + public void preprocess(ServiceModel serviceModel) { + if (!"smithy-rpc-v2-cbor".equals(serviceModel.getMetadata().getProtocol())) { + return; + } + serviceModel.getOperations().forEach((name, op) -> setRequestUri(serviceModel, name, op)); + } + + private void setRequestUri(ServiceModel service, String name, Operation op) { + Http http = op.getHttp(); + String requestUri = http.getRequestUri(); + if (StringUtils.isNotBlank(requestUri) && !"/".equals(requestUri)) { + return; + } + String uri = String.format("/service/%s/operation/%s", service.getMetadata().getTargetPrefix(), op.getName()); + op.getHttp().setRequestUri(uri); + } + + @Override + public void postprocess(IntermediateModel intermediateModel) { + } +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java index 13703cbb61da..9184d096d55b 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java @@ -29,6 +29,7 @@ import software.amazon.awssdk.codegen.model.intermediate.MapModel; import software.amazon.awssdk.codegen.model.intermediate.MemberModel; import software.amazon.awssdk.codegen.model.intermediate.Metadata; +import software.amazon.awssdk.codegen.model.intermediate.Protocol; import software.amazon.awssdk.codegen.model.intermediate.ShapeMarshaller; import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.codegen.model.intermediate.ShapeType; @@ -333,7 +334,8 @@ public static ShapeMarshaller createInputShapeMarshaller(ServiceMetadata service ShapeMarshaller marshaller = new ShapeMarshaller() .withAction(operation.getName()) .withVerb(operation.getHttp().getMethod()) - .withRequestUri(operation.getHttp().getRequestUri()); + .withRequestUri(operation.getHttp().getRequestUri()) + .withSmithyProtocol(getSmithyProtocol(service.getProtocol())); Input input = operation.getInput(); if (input != null) { marshaller.setLocationName(input.getLocationName()); @@ -343,7 +345,7 @@ public static ShapeMarshaller createInputShapeMarshaller(ServiceMetadata service marshaller.setXmlNameSpaceUri(xmlNamespace.getUri()); } } - if (Metadata.isNotRestProtocol(service.getProtocol())) { + if (Metadata.usesOperationIdentifier(service.getProtocol())) { marshaller.setTarget(StringUtils.isEmpty(service.getTargetPrefix()) ? operation.getName() : service.getTargetPrefix() + "." + operation.getName()); @@ -351,4 +353,13 @@ public static ShapeMarshaller createInputShapeMarshaller(ServiceMetadata service return marshaller; } + + private static String getSmithyProtocol(String protocol) { + switch (Protocol.fromValue(protocol)) { + case SMITHY_RPC_V2_CBOR: + return "rpc-v2-cbor"; + default: + return null; + } + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java index ada732afdb2d..bdd2c36ac2d3 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java @@ -545,8 +545,13 @@ public boolean isCborProtocol() { return protocol == Protocol.CBOR; } + public boolean isRpcV2CborProtocol() { + return protocol == Protocol.SMITHY_RPC_V2_CBOR; + } + public boolean isJsonProtocol() { - return protocol == Protocol.CBOR || + return protocol == Protocol.SMITHY_RPC_V2_CBOR || + protocol == Protocol.CBOR || protocol == Protocol.AWS_JSON || protocol == Protocol.REST_JSON; } @@ -563,12 +568,13 @@ public boolean isQueryProtocol() { } /** - * @return True for RESTful protocols. False for all other protocols (RPC, Query, etc). + * @return True for protocols that require an operation identifier to be sent in the `X-Amz-Target` header. */ - public static boolean isNotRestProtocol(String protocol) { + public static boolean usesOperationIdentifier(String protocol) { switch (Protocol.fromValue(protocol)) { case REST_JSON: case REST_XML: + case SMITHY_RPC_V2_CBOR: return false; default: return true; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Protocol.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Protocol.java index 719d088c77e2..545a1add99f3 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Protocol.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Protocol.java @@ -24,7 +24,8 @@ public enum Protocol { REST_JSON("rest-json"), CBOR("cbor"), QUERY("query"), - REST_XML("rest-xml"); + REST_XML("rest-xml"), + SMITHY_RPC_V2_CBOR("smithy-rpc-v2-cbor"); private String protocol; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java index eae9a1b77758..18d8d735908f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java @@ -29,6 +29,8 @@ public class ShapeMarshaller { private String xmlNameSpaceUri; + private String smithyProtocol; + public String getAction() { return action; } @@ -106,4 +108,17 @@ public ShapeMarshaller withXmlNameSpaceUri(String xmlNameSpaceUri) { setXmlNameSpaceUri(xmlNameSpaceUri); return this; } + + public String getSmithyProtocol() { + return smithyProtocol; + } + + public void setSmithyProtocol(String smithyProtocol) { + this.smithyProtocol = smithyProtocol; + } + + public ShapeMarshaller withSmithyProtocol(String smithyProtocol) { + setSmithyProtocol(smithyProtocol); + return this; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java index befb4b49bc28..71585ad21db5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java @@ -405,6 +405,7 @@ static ProtocolSpec getProtocolSpecs(PoetExtension poetExtensions, IntermediateM case AWS_JSON: case REST_JSON: case CBOR: + case SMITHY_RPC_V2_CBOR: return new JsonProtocolSpec(poetExtensions, model); default: throw new RuntimeException("Unknown protocol: " + protocol.name()); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java index dc4a59f92ff7..6d2e174833ae 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java @@ -59,6 +59,7 @@ import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.JsonOperationMetadata; +import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; import software.amazon.awssdk.utils.CompletableFutureUtils; public class JsonProtocolSpec implements ProtocolSpec { @@ -131,6 +132,8 @@ private CodeBlock hasAwsQueryCompatible() { private Class protocolFactoryClass() { if (model.getMetadata().isCborProtocol()) { return AwsCborProtocolFactory.class; + } else if (model.getMetadata().isRpcV2CborProtocol()) { + return SmithyRpcV2CborProtocolFactory.class; } else { return AwsJsonProtocolFactory.class; } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/MarshallerSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/MarshallerSpec.java index 0f2a3229e658..0391892ec427 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/MarshallerSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/MarshallerSpec.java @@ -115,6 +115,7 @@ private MethodSpec marshallMethod() { private MarshallerProtocolSpec getProtocolSpecs(software.amazon.awssdk.codegen.model.intermediate.Protocol protocol) { switch (protocol) { + case SMITHY_RPC_V2_CBOR: case REST_JSON: case CBOR: case AWS_JSON: diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java index eaed3ee87135..c92ed28f67c6 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; import software.amazon.awssdk.protocols.core.ProtocolMarshaller; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.utils.StringUtils; @@ -102,6 +103,13 @@ protected FieldSpec operationInfoField() { initializationCodeBlockBuilder.add(".operationIdentifier($S)", shapeModel.getMarshaller().getTarget()); } + String smithyProtocol = shapeModel.getMarshaller().getSmithyProtocol(); + if (StringUtils.isNotBlank(smithyProtocol)) { + initializationCodeBlockBuilder.add(".putAdditionalMetadata($T.SMITHY_PROTOCOL, $S)", + OperationMetadataAttribute.class, smithyProtocol); + } + + if (shapeModel.isHasStreamingMember()) { initializationCodeBlockBuilder.add(".hasStreamingInput(true)"); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsServiceProtocol.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsServiceProtocol.java index 7f0522413572..8b2ebe354a34 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsServiceProtocol.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsServiceProtocol.java @@ -23,6 +23,7 @@ public enum AwsServiceProtocol { AWS_JSON("json"), REST_JSON("rest-json"), CBOR("cbor"), + SMITHY_RPC_V2_CBOR("smithy-rpc-v2-cbor"), QUERY("query"), REST_XML("rest-xml"); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocol.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocol.java index 98f923f0f114..656642e3fd16 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocol.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocol.java @@ -34,4 +34,9 @@ public enum AwsJsonProtocol { * binary and streaming data. Operation is identified by HTTP verb and resource path combination. */ REST_JSON, + + /** + * RPC protocol that sends all data in the payload as CBOR encoded JSON. + */ + SMITHY_RPC_V2_CBOR, } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 2fa813a5a330..0da4b4f3e902 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -138,7 +138,10 @@ private MetricCollectingHttpResponseHandler timeUnmarshalling(HttpRespons } private StructuredJsonGenerator createGenerator(OperationInfo operationInfo) { - if (operationInfo.hasPayloadMembers() || protocolMetadata.protocol() == AwsJsonProtocol.AWS_JSON) { + AwsJsonProtocol protocol = protocolMetadata.protocol(); + if (operationInfo.hasPayloadMembers() + || protocol == AwsJsonProtocol.AWS_JSON + || protocol == AwsJsonProtocol.SMITHY_RPC_V2_CBOR) { return createGenerator(); } else { return StructuredJsonGenerator.NO_OP; diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java index 5d84ed0a9906..8d02b2ea78f8 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java @@ -135,6 +135,10 @@ public String getContentType() { StructuredJsonGenerator writeStartArray(); + default StructuredJsonGenerator writeStartArray(int size) { + return writeStartArray(); + } + StructuredJsonGenerator writeEndArray(); StructuredJsonGenerator writeNull(); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java index c0a3f46bff05..dc5f56e7ffbb 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java @@ -39,6 +39,7 @@ import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.protocols.core.InstantToString; import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; import software.amazon.awssdk.protocols.core.ProtocolMarshaller; import software.amazon.awssdk.protocols.core.ProtocolUtils; import software.amazon.awssdk.protocols.core.ValueToStringConverter.ValueToString; @@ -161,12 +162,16 @@ private static Map getDefaultTime } private SdkHttpFullRequest.Builder fillBasicRequestParams(OperationInfo operationInfo) { - return ProtocolUtils.createSdkHttpRequest(operationInfo, endpoint) - .applyMutation(b -> { - if (operationInfo.operationIdentifier() != null) { - b.putHeader("X-Amz-Target", operationInfo.operationIdentifier()); - } - }); + SdkHttpFullRequest.Builder requestBuilder = ProtocolUtils.createSdkHttpRequest(operationInfo, endpoint); + String operationIdentifier = operationInfo.operationIdentifier(); + if (operationIdentifier != null) { + requestBuilder.putHeader("X-Amz-Target", operationIdentifier); + } + String smithyProtocol = operationInfo.addtionalMetadata(OperationMetadataAttribute.SMITHY_PROTOCOL); + if (smithyProtocol != null) { + requestBuilder.putHeader("smithy-protocol", smithyProtocol); + } + return requestBuilder; } /** @@ -290,7 +295,9 @@ private void marshallField(SdkField field, Object val) { } private boolean needTopLevelJsonObject() { - return AwsJsonProtocol.AWS_JSON.equals(protocolMetadata.protocol()) + AwsJsonProtocol protocol = protocolMetadata.protocol(); + return protocol == AwsJsonProtocol.AWS_JSON + || protocol == AwsJsonProtocol.SMITHY_RPC_V2_CBOR || (!hasExplicitPayloadMember && hasImplicitPayloadMembers); } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java index a1eb5a77d4f3..c4c5da8a74e1 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java @@ -165,7 +165,7 @@ public void marshall(SdkPojo val, StructuredJsonGenerator jsonGenerator, JsonMar public static final JsonMarshaller> LIST = new BaseJsonMarshaller>() { @Override public void marshall(List list, StructuredJsonGenerator jsonGenerator, JsonMarshallerContext context) { - jsonGenerator.writeStartArray(); + jsonGenerator.writeStartArray(list.size()); for (Object listValue : list) { context.marshall(MarshallLocation.PAYLOAD, listValue); } diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java index f77f084339b3..b2a6e587dcdb 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java @@ -27,6 +27,12 @@ @SdkProtectedApi public final class OperationMetadataAttribute extends AttributeMap.Key { + /** + * Attribute for configuring the smithy-protocol header. + */ + public static final OperationMetadataAttribute SMITHY_PROTOCOL = + new OperationMetadataAttribute<>(String.class); + public OperationMetadataAttribute(Class valueType) { super(valueType); } diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml index 8dde8b80902c..3daf142e8f33 100644 --- a/core/protocols/smithy-rpcv2-protocol/pom.xml +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -31,7 +31,6 @@ https://aws.amazon.com/sdkforjava - diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java new file mode 100644 index 000000000000..e3b76bdba065 --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java @@ -0,0 +1,100 @@ +/* + * 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.protocols.rpcv2; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.protocols.json.JsonContentTypeResolver; +import software.amazon.awssdk.protocols.json.StructuredJsonFactory; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkStructuredRpcV2CborFactory; + +/** + * Protocol factory for RPCv2 CBOR protocol. + */ +@SdkProtectedApi +public final class SmithyRpcV2CborProtocolFactory extends BaseAwsJsonProtocolFactory { + + /** + * Content type resolver implementation for RPC_V2_CBOR enabled services. + */ + private static final JsonContentTypeResolver RPC_V2_CBOR = protocolMetadata -> "application/cbor"; + + private SmithyRpcV2CborProtocolFactory(Builder builder) { + super(builder); + } + + /** + * @return Content type resolver implementation to use. + */ + @Override + protected JsonContentTypeResolver getContentTypeResolver() { + return RPC_V2_CBOR; + } + + /** + * @return Instance of {@link StructuredJsonFactory} to use in creating handlers. + */ + @Override + protected StructuredJsonFactory getSdkFactory() { + return SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY; + } + + /** + * Smithy RPCv2 uses epoch seconds with millisecond decimal precision. + */ + @Override + protected Map getDefaultTimestampFormats() { + return LazyHolder.DEFAULT_TIMESTAMP_FORMATS; + } + + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link SmithyRpcV2CborProtocolFactory}. + */ + public static final class Builder extends BaseAwsJsonProtocolFactory.Builder { + + private Builder() { + } + + public SmithyRpcV2CborProtocolFactory build() { + return new SmithyRpcV2CborProtocolFactory(this); + } + } + + // Lazy initialization holder class idiom + private static class LazyHolder { + private static final Map DEFAULT_TIMESTAMP_FORMATS = + createDefaultTimestampFormats(); + + private LazyHolder() { + } + + static Map createDefaultTimestampFormats() { + Map formats = new EnumMap<>(MarshallLocation.class); + formats.put(MarshallLocation.PAYLOAD, TimestampFormatTrait.Format.UNIX_TIMESTAMP); + return Collections.unmodifiableMap(formats); + + } + } +} diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGenerator.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGenerator.java new file mode 100644 index 000000000000..b7423770bd1b --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGenerator.java @@ -0,0 +1,117 @@ +/* + * 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.protocols.rpcv2.internal; + +import java.io.IOException; +import java.time.Instant; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.protocols.json.SdkJsonGenerator; +import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; +import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory; +import software.amazon.awssdk.thirdparty.jackson.dataformat.cbor.CBORGenerator; + +/** + * Thin wrapper around Jackson's JSON generator for CBOR. + */ +@SdkInternalApi +public final class SdkRpcV2CborGenerator extends SdkJsonGenerator { + + private static final int CBOR_TAG_TIMESTAMP = 1; + + SdkRpcV2CborGenerator(JsonFactory factory, String contentType) { + super(factory, contentType); + } + + /** + * Jackson doesn't have native support for timestamp. As per the RFC 7049 (https://tools.ietf.org/html/rfc7049#section-2.4.1) + * we will need to write a tag and write the epoch. + */ + @Override + public StructuredJsonGenerator writeValue(Instant instant) { + CBORGenerator generator = getGenerator(); + try { + generator.writeTag(CBOR_TAG_TIMESTAMP); + generator.writeNumber(instant.toEpochMilli() / 1000d); + } catch (IOException e) { + throw new JsonGenerationException(e); + } + return this; + } + + @Override + public StructuredJsonGenerator writeStartArray(int size) { + CBORGenerator generator = getGenerator(); + try { + generator.writeStartArray(null, size); + } catch (IOException e) { + throw new JsonGenerationException(e); + } + return this; + } + + @Override + public StructuredJsonGenerator writeValue(double val) { + if (canConvertToLong(val)) { + return writeValue((long) val); + } + CBORGenerator generator = getGenerator(); + try { + generator.writeNumber(val); + } catch (IOException e) { + throw new JsonGenerationException(e); + } + return this; + } + + @Override + public StructuredJsonGenerator writeValue(float val) { + if (canConvertToLong(val)) { + return writeValue((long) val); + } + CBORGenerator generator = getGenerator(); + try { + generator.writeNumber(val); + } catch (IOException e) { + throw new JsonGenerationException(e); + } + return this; + } + + @Override + protected CBORGenerator getGenerator() { + return (CBORGenerator) super.getGenerator(); + } + + /** + * Checks if we can convert the floating point value to a long. If we can we then use the writeNumber(long), alongside with + * having enabled Feature.WRITE_MINIMAL_INTS will allow us to represent the floating point values minimally. + */ + private static boolean canConvertToLong(double value) { + return ((double) (long) value) == value + && value >= Long.MIN_VALUE + && value <= Long.MAX_VALUE; + } + + /** + * Checks if we can convert the floating point value to a long. If we can we then use the writeNumber(long), alongside with + * having enabled Feature.WRITE_MINIMAL_INTS will allow us to represent the floating point values minimally. + */ + private static boolean canConvertToLong(float value) { + return ((float) (long) value) == value + && value >= Long.MIN_VALUE + && value <= Long.MAX_VALUE; + } +} diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkStructuredRpcV2CborFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkStructuredRpcV2CborFactory.java new file mode 100644 index 000000000000..d595715bdd9a --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkStructuredRpcV2CborFactory.java @@ -0,0 +1,55 @@ +/* + * 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.protocols.rpcv2.internal; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.protocols.json.BaseAwsStructuredJsonFactory; +import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; +import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory; +import software.amazon.awssdk.thirdparty.jackson.dataformat.cbor.CBORFactory; +import software.amazon.awssdk.thirdparty.jackson.dataformat.cbor.CBORFactoryBuilder; +import software.amazon.awssdk.thirdparty.jackson.dataformat.cbor.CBORGenerator; + +/** + * Creates generators and protocol handlers for RPCv2 CBOR wire format. + */ +@SdkInternalApi +public final class SdkStructuredRpcV2CborFactory { + + private static final CBORFactory CBOR_FACTORY = new CBORFactoryBuilder(new CBORFactory()) + /* Allows integers to be represented using as little bytes as possible. This is the default, adding here for clarity */ + .enable(CBORGenerator.Feature.WRITE_MINIMAL_INTS) + /* Allows doubles (8 bytes) to be represented as floats (4 bytes) when possible. */ + .enable(CBORGenerator.Feature.WRITE_MINIMAL_DOUBLES) + .build(); + + public static final BaseAwsStructuredJsonFactory SDK_CBOR_FACTORY = + new BaseAwsStructuredJsonFactory(CBOR_FACTORY) { + @Override + protected StructuredJsonGenerator createWriter(JsonFactory jsonFactory, + String contentType) { + return new SdkRpcV2CborGenerator(jsonFactory, contentType); + } + + @Override + public CBORFactory getJsonFactory() { + return CBOR_FACTORY; + } + }; + + private SdkStructuredRpcV2CborFactory() { + } +} diff --git a/core/protocols/smithy-rpcv2-protocol/src/test/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGeneratorTest.java b/core/protocols/smithy-rpcv2-protocol/src/test/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGeneratorTest.java new file mode 100644 index 000000000000..245706950716 --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/test/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborGeneratorTest.java @@ -0,0 +1,217 @@ +/* + * 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.protocols.rpcv2.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import java.util.function.Consumer; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; + +class SdkRpcV2CborGeneratorTest { + private static final byte[] HEX_ARRAY = "0123456789abcdef".getBytes(StandardCharsets.US_ASCII); + + @ParameterizedTest(name = "{index} - {0}") + @MethodSource("testCases") + public void runTestCases(TestCase testCase) { + StructuredJsonGenerator generator = getGenerator(); + testCase.setup.accept(generator); + assertThat(toHexEncoded(generator.getBytes())).isEqualTo(annotatedToHex(testCase.expected)); + } + + public static Collection testCases() { + return Arrays.asList( + // Numbers, minimal encoding + builder("Minimally encodes longs when they fit as a simple value") + .setup( + g -> g.writeStartArray(1) + .writeValue(23L) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=8117" + , "81 # array(1)" + , " 17 # unsigned(23)" + ) + .build() + , builder("Minimally encodes longs when they fit in one byte") + .setup( + g -> g.writeStartArray(1) + .writeValue(255L) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=8118ff" + , "81 # array(1)" + , " 18 ff # unsigned(255)" + ) + .build() + , builder("Minimally encodes longs when they fit in two byte") + .setup( + g -> g.writeStartArray(1) + .writeValue(256L) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=81190100" + , "81 # array(1)" + , " 19 0100 # unsigned(256)" + ) + .build() + , builder("Minimally encodes floats when are equivalent to ints") + .setup( + g -> g.writeStartArray(1) + .writeValue(23.0F) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=8117" + , "81 # array(1)" + , " 17 # unsigned(23)" + ) + .build() + , builder("Minimally encodes doubles when are equivalent to ints") + .setup( + g -> g.writeStartArray(1) + .writeValue(23.0) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=8117" + , "81 # array(1)" + , " 17 # unsigned(23)" + ) + .build() + , builder("Minimally encodes doubles that fit in a float") + .setup( + g -> g.writeStartArray(1) + .writeValue(1.5) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=81fa3fc00000" + , "81 # array(1)" + , " fa 3fc00000 # float(1.5)" + ) + .build() + + , builder("Encodes doubles as doubles when needed") + .setup( + g -> g.writeStartArray(1) + .writeValue(3.1415927) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=81fb400921fb5a7ed197" + , "81 # array(1)" + , " fb 400921fb5a7ed197 # float(3.1415927)" + ) + .build() + // Timestamp as epoch seconds with milliseconds decimal part + , builder("Encodes timestamp as epoch seconds with millisecond decimal part") + .setup( + g -> g.writeStartArray(1) + .writeValue(Instant.parse("2024-08-09T18:13:18.426482Z")) + .writeEndArray() + ) + .expected( + "# https://cbor.nemo157.com/#type=hex&value=81C1FB41D9AD970F9B4396" + , "81 # array(1)" + , " c1 # epoch datetime value, tag(1)" + , " fb 41d9ad970f9b4396 # float(1,723,227,198.426)" + , " # datetime(2024-08-09T18:13:18.426000118Z)" + ) + .build() + ); + } + + static TestCaseBuilder builder(String name) { + return new TestCaseBuilder() + .name(name); + } + + private static StructuredJsonGenerator getGenerator() { + return SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY.createWriter("application/cbor"); + } + + private String annotatedToHex(String... args) { + StringBuilder buf = new StringBuilder(); + for (String arg : args) { + String cleaned = arg.replaceFirst("#.*$", "") + .replaceAll("\\s+", ""); + buf.append(cleaned); + } + return buf.toString(); + } + + public static String toHexEncoded(byte[] bytes) { + byte[] hexChars = new byte[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars, StandardCharsets.UTF_8); + } + + static class TestCase { + private final String name; + private final Consumer setup; + private final String[] expected; + + public TestCase(TestCaseBuilder builder) { + this.name = Objects.requireNonNull(builder.name, "name"); + this.setup = Objects.requireNonNull(builder.setup, "setup"); + this.expected = Objects.requireNonNull(builder.expected, "expected"); + } + + @Override + public String toString() { + return name; + } + } + + static class TestCaseBuilder { + private String name; + private Consumer setup; + private String[] expected; + + public TestCaseBuilder name(String name) { + this.name = name; + return this; + } + + public TestCaseBuilder setup(Consumer setup) { + this.setup = setup; + return this; + } + + public TestCaseBuilder expected(String... expected) { + this.expected = expected; + return this; + } + + public TestCase build() { + return new TestCase(this); + } + } +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/EncodedBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/EncodedBodyAssertion.java new file mode 100644 index 000000000000..de84bf877e5b --- /dev/null +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/EncodedBodyAssertion.java @@ -0,0 +1,40 @@ +/* + * 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.asserts.marshalling; + +import static org.junit.Assert.assertEquals; + +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * Asserts on the body (expected to be CBOR encoded) of the marshalled request. + */ +public class EncodedBodyAssertion extends MarshallingAssertion { + private final String encodedEquals; + + public EncodedBodyAssertion(String encodedEquals) { + this.encodedEquals = encodedEquals; + } + + @Override + protected void doAssert(LoggedRequest actual) throws Exception { + byte[] actualBytes = Base64.getEncoder().encode(actual.getBody()); + String actualValue = new String(actualBytes, StandardCharsets.UTF_8); + assertEquals(encodedEquals, actualValue); + } +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java index d93d93dc2149..1a1301c7bc55 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java @@ -25,6 +25,10 @@ public void setJsonEquals(String jsonEquals) { addAssertion(new JsonBodyAssertion(jsonEquals)); } + public void setEncodedEquals(String encodedEquals) { + addAssertion(new EncodedBodyAssertion(encodedEquals)); + } + public void setXmlEquals(String xmlEquals) { addAssertion(new XmlBodyAssertion(xmlEquals)); } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/GivenResponse.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/GivenResponse.java index 5dfbd15e6a81..870417b63894 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/GivenResponse.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/GivenResponse.java @@ -25,6 +25,7 @@ public class GivenResponse { private Integer statusCode; private Map> headers; private String body; + private String binaryBody; public Integer getStatusCode() { return statusCode; @@ -46,7 +47,15 @@ public String getBody() { return body; } + public String getBinaryBody() { + return binaryBody; + } + public void setBody(String body) { this.body = body; } + + public void setBinaryBody(String body) { + this.binaryBody = body; + } } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/UnmarshallingTestRunner.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/UnmarshallingTestRunner.java index 4560184e88aa..6ee3b88cb010 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/UnmarshallingTestRunner.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/UnmarshallingTestRunner.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; import com.github.tomakehurst.wiremock.client.WireMock; +import java.util.Base64; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.Metadata; import software.amazon.awssdk.core.sync.ResponseTransformer; @@ -108,6 +109,8 @@ private ResponseDefinitionBuilder toResponseBuilder(GivenResponse givenResponse) } if (givenResponse.getBody() != null) { responseBuilder.withBody(givenResponse.getBody()); + } else if (givenResponse.getBinaryBody() != null) { + responseBuilder.withBody(Base64.getDecoder().decode(givenResponse.getBinaryBody())); } else if (metadata.isXmlProtocol()) { // XML Unmarshallers expect at least one level in the XML document. If no body is explicitly // set by the test add a fake one here. diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json new file mode 100644 index 000000000000..62b74014c133 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json @@ -0,0 +1,560 @@ +[ + { + "description": "Serializes null values in lists", + "given": { + "input": { + "sparseStringList": [ + null + ] + } + }, + "when": { + "action": "marshall", + "operation": "SparseNullsOperation" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v3BzcGFyc2VTdHJpbmdMaXN0gfb/" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes recursive structures", + "given": { + "input": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + } + }, + "when": { + "action": "marshall", + "operation": "RecursiveShapes" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes sparse maps", + "given": { + "input": { + "sparseStructMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v29zcGFyc2VTdHJ1Y3RNYXC/Y2Zvb79iaGlldGhlcmX/Y2Jher9iaGljYnll////" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "A request that contains a sparse map of sets", + "given": { + "input": { + "sparseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2xzcGFyc2VTZXRNYXC/YXiAYXmCYWFhYv//" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "given": { + "input": { + "sparseNumberMap": { + "x": 0 + }, + "sparseBooleanMap": { + "x": false + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v29zcGFyc2VOdW1iZXJNYXC/YXgA/3BzcGFyc2VCb29sZWFuTWFwv2F49P//" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes maps", + "given": { + "input": { + "denseStructMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v25kZW5zZVN0cnVjdE1hcL9jZm9vv2JoaWV0aGVyZf9jYmF6v2JoaWNieWX///8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "given": { + "input": { + "denseNumberMap": { + "x": 0 + }, + "denseBooleanMap": { + "x": false + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v25kZW5zZU51bWJlck1hcL9heAD/b2RlbnNlQm9vbGVhbk1hcL9hePT//w==" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "A request that contains a dense map of sets.", + "given": { + "input": { + "denseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2tkZW5zZVNldE1hcL9heIBheYJhYWFi//8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes RpcV2 Cbor lists", + "given": { + "input": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238000, + 1398796238000 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ], + "blobList": [ + "foo", + "bar" + ] + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborLists" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2pzdHJpbmdMaXN0gmNmb29jYmFyaXN0cmluZ1NldIJjZm9vY2JhcmtpbnRlZ2VyTGlzdIIBAmtib29sZWFuTGlzdIL19G10aW1lc3RhbXBMaXN0gsH7QdTX+/OAAADB+0HU1/vzgAAAaGVudW1MaXN0gmNGb29hMGtpbnRFbnVtTGlzdIIBAnBuZXN0ZWRTdHJpbmdMaXN0goJjZm9vY2JhcoJjYmF6Y3F1eG1zdHJ1Y3R1cmVMaXN0gr9hYWExYWJhMv+/YWFhM2FiYTT/aGJsb2JMaXN0gkNmb29DYmFy/w==" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes empty JSON lists", + "given": { + "input": { + "stringList": [] + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborLists" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2pzdHJpbmdMaXN0gP8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes empty JSON definite length lists", + "given": { + "input": { + "stringList": [] + } + }, + "when": { + "action": "marshall", + "operation": "RpcV2CborLists" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2pzdHJpbmdMaXN0gP8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Serializes simple scalar properties", + "given": { + "input": { + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 5, + "doubleValue": 1.889, + "floatValue": 7.625, + "integerValue": 256, + "longValue": 9873, + "shortValue": 9898, + "stringValue": "simple", + "blobValue": "foo" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZWlibG9iVmFsdWVDZm9v/w==" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "RpcV2 Cbor should not serialize null structure values", + "given": { + "input": { + "stringValue": null + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v/8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Supports handling NaN float values.", + "given": { + "input": { + "doubleValue": "NaN", + "floatValue": "NaN" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2tkb3VibGVWYWx1Zft/+AAAAAAAAGpmbG9hdFZhbHVl+n/AAAD/" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Supports handling Infinity float values.", + "given": { + "input": { + "doubleValue": "Infinity", + "floatValue": "Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2tkb3VibGVWYWx1Zfp/gAAAamZsb2F0VmFsdWX6f4AAAP8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "Supports handling Infinity float values.", + "given": { + "input": { + "doubleValue": "-Infinity", + "floatValue": "-Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v2tkb3VibGVWYWx1Zfr/gAAAamZsb2F0VmFsdWX6/4AAAP8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "When input is empty we write CBOR equivalent of {}", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "OptionalInputOutput" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v/8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + }, + { + "description": "When Input structure is empty we write CBOR equivalent of {}", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "EmptyInputOutput" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "v/8=" + }, + "headers": { + "contains": { + "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor" + } + } + } + } + } +] \ No newline at end of file diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json new file mode 100644 index 000000000000..bc82842c02d5 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json @@ -0,0 +1,667 @@ +[ + { + "description": "Ensures that clients can correctly parse float16 +Inf.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWV2YWx1Zfl8AA==" + } + }, + "when": { + "action": "unmarshall", + "operation": "Float16" + }, + "then": { + "deserializedAs": { + "value": "Infinity" + } + } + }, + { + "description": "Ensures that clients can correctly parse float16 -Inf.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWV2YWx1Zfn8AA==" + } + }, + "when": { + "action": "unmarshall", + "operation": "Float16" + }, + "then": { + "deserializedAs": { + "value": "-Infinity" + } + } + }, + { + "description": "Ensures that clients can correctly parse float16 NaN with high LSB.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWV2YWx1Zfl8AQ==" + } + }, + "when": { + "action": "unmarshall", + "operation": "Float16" + }, + "then": { + "deserializedAs": { + "value": "NaN" + } + } + }, + { + "description": "Ensures that clients can correctly parse float16 NaN with high MSB.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWV2YWx1Zfl+AA==" + } + }, + "when": { + "action": "unmarshall", + "operation": "Float16" + }, + "then": { + "deserializedAs": { + "value": "NaN" + } + } + }, + { + "description": "Deserializes null values in lists", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v3BzcGFyc2VTdHJpbmdMaXN0n/b//w==" + } + }, + "when": { + "action": "unmarshall", + "operation": "SparseNullsOperation" + }, + "then": { + "deserializedAs": { + "sparseStringList": [ + null + ] + } + } + }, + { + "description": "Ensures that clients can correctly parse timestamps with fractional seconds", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2hkYXRldGltZcH7Qcw32zgPvnf/" + } + }, + "when": { + "action": "unmarshall", + "operation": "FractionalSeconds" + }, + "then": { + "deserializedAs": { + "datetime": 946845296123 + } + } + }, + { + "description": "Serializes recursive structures", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "RecursiveShapes" + }, + "then": { + "deserializedAs": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + } + } + }, + { + "description": "Deserializes recursive structures encoded using a map with definite length", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWZuZXN0ZWSiY2Zvb2RGb28xZm5lc3RlZKJjYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyomNmb29kRm9vMmZuZXN0ZWShY2JhcmRCYXIy" + } + }, + "when": { + "action": "unmarshall", + "operation": "RecursiveShapes" + }, + "then": { + "deserializedAs": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + } + } + }, + { + "description": "Deserializes sparse maps", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v29zcGFyc2VTdHJ1Y3RNYXC/Y2Zvb79iaGlldGhlcmX/Y2Jher9iaGljYnll////" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "deserializedAs": { + "sparseStructMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + } + } + }, + { + "description": "A response that contains a sparse map of sets", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2xzcGFyc2VTZXRNYXC/YXmfYWFhYv9heJ////8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "deserializedAs": { + "sparseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + } + } + }, + { + "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v29zcGFyc2VOdW1iZXJNYXC/YXgA/3BzcGFyc2VCb29sZWFuTWFwv2F49P//" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborSparseMaps" + }, + "then": { + "deserializedAs": { + "sparseNumberMap": { + "x": 0 + }, + "sparseBooleanMap": { + "x": false + } + } + } + }, + { + "description": "Deserializes maps", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oW5kZW5zZVN0cnVjdE1hcKJjZm9voWJoaWV0aGVyZWNiYXqhYmhpY2J5ZQ==" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "deserializedAs": { + "denseStructMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + } + } + }, + { + "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "given": { + "response": { + "status_code": 200, + "binaryBody": "om5kZW5zZU51bWJlck1hcKFheABvZGVuc2VCb29sZWFuTWFwoWF49A==" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "deserializedAs": { + "denseNumberMap": { + "x": 0 + }, + "denseBooleanMap": { + "x": false + } + } + } + }, + { + "description": "A response that contains a dense map of sets", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWtkZW5zZVNldE1hcKJheIBheYJhYWFi" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborDenseMaps" + }, + "then": { + "deserializedAs": { + "denseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + } + } + }, + { + "description": "Serializes RpcV2 Cbor lists", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2pzdHJpbmdMaXN0n2Nmb29jYmFy/2lzdHJpbmdTZXSfY2Zvb2NiYXL/a2ludGVnZXJMaXN0nwEC/2tib29sZWFuTGlzdJ/19P9tdGltZXN0YW1wTGlzdJ/B+0HU1/vzgAAAwftB1Nf784AAAP9oZW51bUxpc3SfY0Zvb2Ew/2tpbnRFbnVtTGlzdJ8BAv9wbmVzdGVkU3RyaW5nTGlzdJ+fY2Zvb2NiYXL/n2NiYXpjcXV4//9tc3RydWN0dXJlTGlzdJ+/YWFhMWFiYTL/v2FhYTNhYmE0//9oYmxvYkxpc3SfQ2Zvb0NiYXL//w==" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborLists" + }, + "then": { + "deserializedAs": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238000, + 1398796238000 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ], + "blobList": [ + "foo", + "bar" + ] + } + } + }, + { + "description": "Serializes empty RpcV2 Cbor lists", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2pzdHJpbmdMaXN0n///" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborLists" + }, + "then": { + "deserializedAs": { + "stringList": [] + } + } + }, + { + "description": "Can deserialize indefinite length text strings inside an indefinite length list", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2pzdHJpbmdMaXN0n394HUFuIGV4YW1wbGUgaW5kZWZpbml0ZSBzdHJpbmcsdyB3aGljaCB3aWxsIGJlIGNodW5rZWQsbiBvbiBlYWNoIGNvbW1h/394NUFub3RoZXIgZXhhbXBsZSBpbmRlZmluaXRlIHN0cmluZyB3aXRoIG9ubHkgb25lIGNodW5r/3ZUaGlzIGlzIGEgcGxhaW4gc3RyaW5n//8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborLists" + }, + "then": { + "deserializedAs": { + "stringList": [ + "An example indefinite string, which will be chunked, on each comma", + "Another example indefinite string with only one chunk", + "This is a plain string" + ] + } + } + }, + { + "description": "Can deserialize indefinite length text strings inside a definite length list", + "given": { + "response": { + "status_code": 200, + "binaryBody": "oWpzdHJpbmdMaXN0g394HUFuIGV4YW1wbGUgaW5kZWZpbml0ZSBzdHJpbmcsdyB3aGljaCB3aWxsIGJlIGNodW5rZWQsbiBvbiBlYWNoIGNvbW1h/394NUFub3RoZXIgZXhhbXBsZSBpbmRlZmluaXRlIHN0cmluZyB3aXRoIG9ubHkgb25lIGNodW5r/3ZUaGlzIGlzIGEgcGxhaW4gc3RyaW5n" + } + }, + "when": { + "action": "unmarshall", + "operation": "RpcV2CborLists" + }, + "then": { + "deserializedAs": { + "stringList": [ + "An example indefinite string, which will be chunked, on each comma", + "Another example indefinite string with only one chunk", + "This is a plain string" + ] + } + } + }, + { + "description": "Serializes simple scalar properties", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb2//" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 5, + "doubleValue": 1.889, + "floatValue": 7.625, + "integerValue": 256, + "shortValue": 9898, + "stringValue": "simple", + "blobValue": "foo" + } + } + }, + { + "description": "Deserializes simple scalar properties encoded using a map with definite length", + "given": { + "response": { + "status_code": 200, + "binaryBody": "qXB0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb28=" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 5, + "doubleValue": 1.889, + "floatValue": 7.625, + "integerValue": 256, + "shortValue": 9898, + "stringValue": "simple", + "blobValue": "foo" + } + } + }, + { + "description": "RpcV2 Cbor should not deserialize null structure values", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2tzdHJpbmdWYWx1Zfb/" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": {} + } + }, + { + "description": "Supports handling NaN float values.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2tkb3VibGVWYWx1Zft/+AAAAAAAAGpmbG9hdFZhbHVl+n/AAAD/" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "doubleValue": "NaN", + "floatValue": "NaN" + } + } + }, + { + "description": "Supports handling Infinity float values.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2tkb3VibGVWYWx1Zft/8AAAAAAAAGpmbG9hdFZhbHVl+n+AAAD/" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "doubleValue": "Infinity", + "floatValue": "Infinity" + } + } + }, + { + "description": "Supports handling Negative Infinity float values.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2tkb3VibGVWYWx1Zfv/8AAAAAAAAGpmbG9hdFZhbHVl+v+AAAD/" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "doubleValue": "-Infinity", + "floatValue": "-Infinity" + } + } + }, + { + "description": "Supports upcasting from a smaller byte representation of the same data type.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2tkb3VibGVWYWx1Zfk+AGpmbG9hdFZhbHVl+UegbGludGVnZXJWYWx1ZRg4aWxvbmdWYWx1ZRkBAGpzaG9ydFZhbHVlCv8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "doubleValue": 1.5, + "floatValue": 7.625, + "integerValue": 56, + "longValue": 256, + "shortValue": 10 + } + } + }, + { + "description": "The client should skip over additional fields that are not part of the structure. This allows a\nclient generated against an older Smithy model to be able to communicate with a server that is\ngenerated against a newer Smithy model.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABrZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 5, + "doubleValue": 1.889, + "floatValue": 7.625, + "integerValue": 256, + "longValue": 9873, + "shortValue": 9898, + "stringValue": "simple", + "blobValue": "foo" + } + } + }, + { + "description": "When output is empty we write CBOR equivalent of {}", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v/8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "OptionalInputOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "description": "When output structure is empty we write CBOR equivalent of {}", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v/8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "EmptyInputOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "description": "Clients should accept a CBOR empty struct if there is no output.", + "given": { + "response": { + "status_code": 200, + "binaryBody": "v/8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputOutput" + }, + "then": { + "deserializedAs": {} + } + } +] \ No newline at end of file diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/smithy-rpcv2-suite.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/smithy-rpcv2-suite.json new file mode 100644 index 000000000000..a930cd475534 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/smithy-rpcv2-suite.json @@ -0,0 +1,6 @@ +{ + "testCases": [ + "cases/smithy-rpcv2-input.json", + "cases/smithy-rpcv2-output.json" + ] +} diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index 0281e03e1279..43b11f067ced 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -57,13 +57,11 @@ aws-xml-protocol ${awsjavasdk.version} - software.amazon.awssdk protocol-core diff --git a/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/customization.config b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/customization.config new file mode 100644 index 000000000000..ec7c8d355d50 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/customization.config @@ -0,0 +1,3 @@ +{ + "skipEndpointTestGeneration": true +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-rule-set.json b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-rule-set.json new file mode 100644 index 000000000000..5846e263b355 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-rule-set.json @@ -0,0 +1,59 @@ +{ + "version": "1.3", + "parameters": { + "Region": { + "builtIn": "AWS::Region", + "required": true, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + }, + "UseDualStack": { + "builtIn": "AWS::UseDualStack", + "required": true, + "default": false, + "documentation": "When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.", + "type": "Boolean" + }, + "UseFIPS": { + "builtIn": "AWS::UseFIPS", + "required": true, + "default": false, + "documentation": "When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.", + "type": "Boolean" + }, + "Endpoint": { + "builtIn": "SDK::Endpoint", + "required": false, + "documentation": "Override the endpoint used to send this request", + "type": "String" + } + }, + "rules": [ + { + "conditions": [ + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": { + "ref": "Endpoint" + }, + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "jsonrpc" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-tests.json b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-tests.json new file mode 100644 index 000000000000..f94902ff9d99 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/endpoint-tests.json @@ -0,0 +1,5 @@ +{ + "testCases": [ + ], + "version": "1.0" +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/service-2.json new file mode 100644 index 000000000000..0cc5eeb51db6 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/rpcv2/service-2.json @@ -0,0 +1,546 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2023-03-10", + "auth":["aws.auth#sigv4"], + "endpointPrefix":"smithyrpcv2protocol", + "protocol":"smithy-rpc-v2-cbor", + "protocols":["smithy-rpc-v2-cbor"], + "serviceFullName":"RpcV2 Protocol Service", + "serviceId":"SmithyRpcV2Protocol", + "signatureVersion":"v4", + "signingName":"execute-api", + "targetPrefix":"RpcV2Protocol", + "uid":"smithy-rpcv2protocol-2023-03-10" + }, + "operations":{ + "EmptyInputOutput":{ + "name":"EmptyInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"EmptyStructure"}, + "output":{"shape":"EmptyStructure"} + }, + "Float16":{ + "name":"Float16", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"Float16Output"} + }, + "FractionalSeconds":{ + "name":"FractionalSeconds", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"FractionalSecondsOutput"} + }, + "GreetingWithErrors":{ + "name":"GreetingWithErrors", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"GreetingWithErrorsOutput"}, + "errors":[ + {"shape":"ComplexError"}, + {"shape":"InvalidGreeting"} + ], + "idempotent":true + }, + "NoInputOutput":{ + "name":"NoInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + } + }, + "OperationWithDefaults":{ + "name":"OperationWithDefaults", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"OperationWithDefaultsInput"}, + "output":{"shape":"OperationWithDefaultsOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "OptionalInputOutput":{ + "name":"OptionalInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SimpleStructure"}, + "output":{"shape":"SimpleStructure"} + }, + "RecursiveShapes":{ + "name":"RecursiveShapes", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RecursiveShapesInputOutput"}, + "output":{"shape":"RecursiveShapesInputOutput"} + }, + "RpcV2CborDenseMaps":{ + "name":"RpcV2CborDenseMaps", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborDenseMapsInputOutput"}, + "output":{"shape":"RpcV2CborDenseMapsInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "RpcV2CborLists":{ + "name":"RpcV2CborLists", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborListInputOutput"}, + "output":{"shape":"RpcV2CborListInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ], + "idempotent":true + }, + "RpcV2CborSparseMaps":{ + "name":"RpcV2CborSparseMaps", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborSparseMapsInputOutput"}, + "output":{"shape":"RpcV2CborSparseMapsInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "SimpleScalarProperties":{ + "name":"SimpleScalarProperties", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SimpleScalarStructure"}, + "output":{"shape":"SimpleScalarStructure"} + }, + "SparseNullsOperation":{ + "name":"SparseNullsOperation", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SparseNullsOperationInputOutput"}, + "output":{"shape":"SparseNullsOperationInputOutput"} + } + }, + "shapes":{ + "Blob":{"type":"blob"}, + "BlobList":{ + "type":"list", + "member":{"shape":"Blob"} + }, + "Boolean":{ + "type":"boolean", + "box":true + }, + "BooleanList":{ + "type":"list", + "member":{"shape":"Boolean"} + }, + "Byte":{ + "type":"byte", + "box":true + }, + "ClientOptionalDefaults":{ + "type":"structure", + "members":{ + "member":{"shape":"Integer"} + } + }, + "ComplexError":{ + "type":"structure", + "members":{ + "TopLevel":{"shape":"String"}, + "Nested":{"shape":"ComplexNestedErrorData"} + }, + "exception":true + }, + "ComplexNestedErrorData":{ + "type":"structure", + "members":{ + "Foo":{"shape":"String"} + } + }, + "DateTime":{ + "type":"timestamp" + }, + "Defaults":{ + "type":"structure", + "members":{ + "defaultString":{"shape":"String"}, + "defaultBoolean":{"shape":"Boolean"}, + "defaultList":{"shape":"TestStringList"}, + "defaultTimestamp":{"shape":"Timestamp"}, + "defaultBlob":{"shape":"Blob"}, + "defaultByte":{"shape":"Byte"}, + "defaultShort":{"shape":"Short"}, + "defaultInteger":{"shape":"Integer"}, + "defaultLong":{"shape":"Long"}, + "defaultFloat":{"shape":"Float"}, + "defaultDouble":{"shape":"Double"}, + "defaultMap":{"shape":"TestStringMap"}, + "defaultEnum":{"shape":"TestEnum"}, + "defaultIntEnum":{"shape":"TestIntEnum"}, + "emptyString":{"shape":"String"}, + "falseBoolean":{"shape":"Boolean"}, + "emptyBlob":{"shape":"Blob"}, + "zeroByte":{"shape":"Byte"}, + "zeroShort":{"shape":"Short"}, + "zeroInteger":{"shape":"Integer"}, + "zeroLong":{"shape":"Long"}, + "zeroFloat":{"shape":"Float"}, + "zeroDouble":{"shape":"Double"} + } + }, + "DenseBooleanMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Boolean"} + }, + "DenseNumberMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Integer"} + }, + "DenseSetMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"StringSet"} + }, + "DenseStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "DenseStructMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"GreetingStruct"} + }, + "Double":{ + "type":"double", + "box":true + }, + "EmptyStructure":{ + "type":"structure", + "members":{ + } + }, + "Float":{ + "type":"float", + "box":true + }, + "Float16Output":{ + "type":"structure", + "members":{ + "value":{"shape":"Double"} + } + }, + "FooEnum":{ + "type":"string", + "enum":[ + "Foo", + "Baz", + "Bar" + ] + }, + "FooEnumList":{ + "type":"list", + "member":{"shape":"FooEnum"} + }, + "FractionalSecondsOutput":{ + "type":"structure", + "members":{ + "datetime":{"shape":"DateTime"} + } + }, + "GreetingStruct":{ + "type":"structure", + "members":{ + "hi":{"shape":"String"} + } + }, + "GreetingWithErrorsOutput":{ + "type":"structure", + "members":{ + "greeting":{"shape":"String"} + } + }, + "Integer":{ + "type":"integer", + "box":true + }, + "IntegerEnum":{ + "type":"integer", + "box":true + }, + "IntegerEnumList":{ + "type":"list", + "member":{"shape":"IntegerEnum"} + }, + "IntegerList":{ + "type":"list", + "member":{"shape":"Integer"} + }, + "InvalidGreeting":{ + "type":"structure", + "members":{ + "Message":{"shape":"String"} + }, + "exception":true + }, + "Long":{ + "type":"long", + "box":true + }, + "NestedStringList":{ + "type":"list", + "member":{"shape":"StringList"} + }, + "OperationWithDefaultsInput":{ + "type":"structure", + "members":{ + "defaults":{"shape":"Defaults"}, + "clientOptionalDefaults":{"shape":"ClientOptionalDefaults"}, + "topLevelDefault":{"shape":"String"}, + "otherTopLevelDefault":{"shape":"Integer"} + } + }, + "OperationWithDefaultsOutput":{ + "type":"structure", + "members":{ + "defaultString":{"shape":"String"}, + "defaultBoolean":{"shape":"Boolean"}, + "defaultList":{"shape":"TestStringList"}, + "defaultTimestamp":{"shape":"Timestamp"}, + "defaultBlob":{"shape":"Blob"}, + "defaultByte":{"shape":"Byte"}, + "defaultShort":{"shape":"Short"}, + "defaultInteger":{"shape":"Integer"}, + "defaultLong":{"shape":"Long"}, + "defaultFloat":{"shape":"Float"}, + "defaultDouble":{"shape":"Double"}, + "defaultMap":{"shape":"TestStringMap"}, + "defaultEnum":{"shape":"TestEnum"}, + "defaultIntEnum":{"shape":"TestIntEnum"}, + "emptyString":{"shape":"String"}, + "falseBoolean":{"shape":"Boolean"}, + "emptyBlob":{"shape":"Blob"}, + "zeroByte":{"shape":"Byte"}, + "zeroShort":{"shape":"Short"}, + "zeroInteger":{"shape":"Integer"}, + "zeroLong":{"shape":"Long"}, + "zeroFloat":{"shape":"Float"}, + "zeroDouble":{"shape":"Double"} + } + }, + "RecursiveShapesInputOutput":{ + "type":"structure", + "members":{ + "nested":{"shape":"RecursiveShapesInputOutputNested1"} + } + }, + "RecursiveShapesInputOutputNested1":{ + "type":"structure", + "members":{ + "foo":{"shape":"String"}, + "nested":{"shape":"RecursiveShapesInputOutputNested2"} + } + }, + "RecursiveShapesInputOutputNested2":{ + "type":"structure", + "members":{ + "bar":{"shape":"String"}, + "recursiveMember":{"shape":"RecursiveShapesInputOutputNested1"} + } + }, + "RpcV2CborDenseMapsInputOutput":{ + "type":"structure", + "members":{ + "denseStructMap":{"shape":"DenseStructMap"}, + "denseNumberMap":{"shape":"DenseNumberMap"}, + "denseBooleanMap":{"shape":"DenseBooleanMap"}, + "denseStringMap":{"shape":"DenseStringMap"}, + "denseSetMap":{"shape":"DenseSetMap"} + } + }, + "RpcV2CborListInputOutput":{ + "type":"structure", + "members":{ + "stringList":{"shape":"StringList"}, + "stringSet":{"shape":"StringSet"}, + "integerList":{"shape":"IntegerList"}, + "booleanList":{"shape":"BooleanList"}, + "timestampList":{"shape":"TimestampList"}, + "enumList":{"shape":"FooEnumList"}, + "intEnumList":{"shape":"IntegerEnumList"}, + "nestedStringList":{"shape":"NestedStringList"}, + "structureList":{"shape":"StructureList"}, + "blobList":{"shape":"BlobList"} + } + }, + "RpcV2CborSparseMapsInputOutput":{ + "type":"structure", + "members":{ + "sparseStructMap":{"shape":"SparseStructMap"}, + "sparseNumberMap":{"shape":"SparseNumberMap"}, + "sparseBooleanMap":{"shape":"SparseBooleanMap"}, + "sparseStringMap":{"shape":"SparseStringMap"}, + "sparseSetMap":{"shape":"SparseSetMap"} + } + }, + "Short":{ + "type":"short", + "box":true + }, + "SimpleScalarStructure":{ + "type":"structure", + "members":{ + "trueBooleanValue":{"shape":"Boolean"}, + "falseBooleanValue":{"shape":"Boolean"}, + "byteValue":{"shape":"Byte"}, + "doubleValue":{"shape":"Double"}, + "floatValue":{"shape":"Float"}, + "integerValue":{"shape":"Integer"}, + "longValue":{"shape":"Long"}, + "shortValue":{"shape":"Short"}, + "stringValue":{"shape":"String"}, + "blobValue":{"shape":"Blob"} + } + }, + "SimpleStructure":{ + "type":"structure", + "members":{ + "value":{"shape":"String"} + } + }, + "SparseBooleanMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Boolean"} + }, + "SparseNullsOperationInputOutput":{ + "type":"structure", + "members":{ + "sparseStringList":{"shape":"SparseStringList"}, + "sparseStringMap":{"shape":"SparseStringMap"} + } + }, + "SparseNumberMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Integer"} + }, + "SparseSetMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"StringSet"} + }, + "SparseStringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "SparseStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "SparseStructMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"GreetingStruct"} + }, + "String":{"type":"string"}, + "StringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "StringSet":{ + "type":"list", + "member":{"shape":"String"} + }, + "StructureList":{ + "type":"list", + "member":{"shape":"StructureListMember"} + }, + "StructureListMember":{ + "type":"structure", + "members":{ + "a":{"shape":"String"}, + "b":{"shape":"String"} + } + }, + "TestEnum":{ + "type":"string", + "enum":[ + "FOO", + "BAR", + "BAZ" + ] + }, + "TestIntEnum":{ + "type":"integer", + "box":true + }, + "TestStringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "TestStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "Timestamp":{"type":"timestamp"}, + "TimestampList":{ + "type":"list", + "member":{"shape":"Timestamp"} + }, + "ValidationException":{ + "type":"structure", + "required":["message"], + "members":{ + "message":{"shape":"String"}, + "fieldList":{"shape":"ValidationExceptionFieldList"} + }, + "exception":true + }, + "ValidationExceptionField":{ + "type":"structure", + "required":[ + "path", + "message" + ], + "members":{ + "path":{"shape":"String"}, + "message":{"shape":"String"} + } + }, + "ValidationExceptionFieldList":{ + "type":"list", + "member":{"shape":"ValidationExceptionField"} + } + } +} diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/SmithyRpcV2CborProtocolTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/SmithyRpcV2CborProtocolTest.java new file mode 100644 index 000000000000..96bdb7edaeb4 --- /dev/null +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/SmithyRpcV2CborProtocolTest.java @@ -0,0 +1,51 @@ +/* + * 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 java.io.IOException; +import java.util.List; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import software.amazon.awssdk.protocol.ProtocolTestSuiteLoader; +import software.amazon.awssdk.protocol.model.TestCase; +import software.amazon.awssdk.protocol.runners.ProtocolTestRunner; + +@RunWith(Parameterized.class) +public class SmithyRpcV2CborProtocolTest { + + private static final ProtocolTestSuiteLoader TEST_SUITE_LOADER = new ProtocolTestSuiteLoader(); + private static ProtocolTestRunner testRunner; + + @Parameterized.Parameter + public TestCase testCase; + + @Parameterized.Parameters(name = "{0}") + public static List data() throws IOException { + return TEST_SUITE_LOADER.load("smithy-rpcv2-suite.json"); + } + + @BeforeClass + public static void setupFixture() { + testRunner = new ProtocolTestRunner("/models/smithyrpcv2protocol-2023-03-10-intermediate.json"); + } + + @Test + public void runProtocolTest() throws Exception { + testRunner.runTest(testCase); + } +} From ea61e301c83b43daa09785db890b3cb51ffc9ba7 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Fri, 16 Aug 2024 12:35:53 -0700 Subject: [PATCH 07/14] Support for operation without input defined (#5512) * Support for operation without input defined * Fix a checkstyle issue * Code clean up * Code clean up 2 * Rewrite the condition to conjunctive normal form --- .../awssdk/codegen/AddEmptyInputShape.java | 4 +- .../DefaultProtocolMetadataConstants.java | 51 ++++++++ .../internal/ProtocolMetadataConstants.java | 51 ++++++++ .../internal/ProtocolMetadataDefault.java | 72 +++++++++++ .../amazon/awssdk/codegen/internal/Utils.java | 18 +-- .../model/intermediate/ShapeMarshaller.java | 29 +++-- .../protocols/CodegenSerializer.java | 113 ++++++++++++++++++ .../protocols/CodegenSerializerResolver.java | 55 +++++++++ .../protocols/JsonMarshallerSpec.java | 58 ++++++++- .../json/BaseAwsJsonProtocolFactory.java | 24 +++- .../marshall/JsonProtocolMarshaller.java | 8 +- .../core/OperationMetadataAttribute.java | 20 +++- .../suites/cases/smithy-rpcv2-input.json | 36 +++++- 13 files changed, 498 insertions(+), 41 deletions(-) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/internal/DefaultProtocolMetadataConstants.java create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataConstants.java create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializer.java create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializerResolver.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/AddEmptyInputShape.java b/codegen/src/main/java/software/amazon/awssdk/codegen/AddEmptyInputShape.java index 3b1c95677796..fcb5c46a7e50 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/AddEmptyInputShape.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/AddEmptyInputShape.java @@ -15,7 +15,7 @@ package software.amazon.awssdk.codegen; -import static software.amazon.awssdk.codegen.internal.Utils.createInputShapeMarshaller; +import static software.amazon.awssdk.codegen.internal.Utils.createSyntheticInputShapeMarshaller; import static software.amazon.awssdk.codegen.internal.Utils.unCapitalize; import java.util.HashMap; @@ -75,7 +75,7 @@ private Map addEmptyInputShapes( shape.setVariable(inputVariable); shape.setMarshaller( - createInputShapeMarshaller(serviceModel.getMetadata(), operation)); + createSyntheticInputShapeMarshaller(serviceModel.getMetadata(), operation)); emptyInputShapes.put(inputShape, shape); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/DefaultProtocolMetadataConstants.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/DefaultProtocolMetadataConstants.java new file mode 100644 index 000000000000..7c9bf84f9c95 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/DefaultProtocolMetadataConstants.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.internal; + +import java.util.AbstractMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; +import software.amazon.awssdk.utils.AttributeMap; + +/** + * Default implementation of {@link ProtocolMetadataConstants}. + */ +public final class DefaultProtocolMetadataConstants implements ProtocolMetadataConstants { + private final Set, OperationMetadataAttribute>> knownKeys = new LinkedHashSet<>(); + private final AttributeMap.Builder map = AttributeMap.builder(); + + @Override + public List, OperationMetadataAttribute>> keys() { + return knownKeys.stream().filter(x -> map.get(x.getValue()) != null).collect(Collectors.toList()); + } + + @Override + public T put(Class containingClass, OperationMetadataAttribute key, T value) { + knownKeys.add(new AbstractMap.SimpleEntry<>(containingClass, key)); + T oldValue = map.get(key); + map.put(key, value); + return oldValue; + } + + @Override + public T get(OperationMetadataAttribute key) { + return map.get(key); + } +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataConstants.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataConstants.java new file mode 100644 index 000000000000..2384ca7977ca --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataConstants.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.internal; + +import java.util.List; +import java.util.Map; +import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; + +/** + * Keeps the set of {@link OperationMetadataAttribute} constants attributes per operation/protocol. This is used to codegen + * those constant values. + */ +public interface ProtocolMetadataConstants { + + /** + * Returns the list of keys sets. The {@link Map.Entry} contains as key the class containing the key field and the value + * contains the key constant itself. The class is needed to properly codegen a reference to the key. + * @return + */ + List, OperationMetadataAttribute>> keys(); + + /** + * Adds an operation metadata to the set of constants. + */ + T put(Class containingClass, OperationMetadataAttribute key, T value); + + /** + * Adds an operation metadata to the set of constants. + */ + default T put(OperationMetadataAttribute key, T value) { + return put(key.getClass(), key, value); + } + + /** + * Gets the constant value for the operation metadata key. + */ + T get(OperationMetadataAttribute key); +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java new file mode 100644 index 000000000000..ca7c346bd19c --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java @@ -0,0 +1,72 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.internal; + +import software.amazon.awssdk.codegen.model.intermediate.Protocol; +import software.amazon.awssdk.codegen.model.intermediate.ShapeMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.utils.MapUtils; + +/** + * Enum that maps protocol to metadata attribute constants for a given operation. + */ +public enum ProtocolMetadataDefault { + + SMITHY_RPC_V2_CBOR(Protocol.SMITHY_RPC_V2_CBOR) { + public ProtocolMetadataConstants protocolMetadata(ShapeMarshaller shapeMarshaller) { + ProtocolMetadataConstants attributes = new DefaultProtocolMetadataConstants(); + + // Smithy RPCv2 requires the header "smithy-protocol" with value "rpc-v2-cbor" + // See https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#requests. + attributes.put(BaseAwsJsonProtocolFactory.class, + BaseAwsJsonProtocolFactory.HTTP_EXTRA_HEADERS, + MapUtils.of("smithy-protocol", "rpc-v2-cbor")); + + // If the shape is synthetic that means that no-input was defined in the model. For this + // case the protocol requires to send an empty body with no content-type. See + // https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#requests. + // To accomplish this we use a no-op JSON generator. Otherwise, we serialize the input + // even when no members are defined. + attributes.put(BaseAwsJsonProtocolFactory.class, + BaseAwsJsonProtocolFactory.USE_NO_OP_GENERATOR, + shapeMarshaller.getIsSynthetic()); + return attributes; + } + }, + DEFAULT(null); + + private final Protocol protocol; + + ProtocolMetadataDefault(Protocol protocol) { + this.protocol = protocol; + } + + /** + * Returns a function that maps from a {@link ShapeMarshaller} to a set of protocol metadata constants that we codegen. + */ + public ProtocolMetadataConstants protocolMetadata(ShapeMarshaller shapeMarshaller) { + return new DefaultProtocolMetadataConstants(); + } + + public static ProtocolMetadataDefault from(Protocol protocol) { + for (ProtocolMetadataDefault value : values()) { + if (value.protocol == protocol) { + return value; + } + } + return DEFAULT; + } +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java index 9184d096d55b..8a2f490bcd36 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/Utils.java @@ -29,7 +29,6 @@ import software.amazon.awssdk.codegen.model.intermediate.MapModel; import software.amazon.awssdk.codegen.model.intermediate.MemberModel; import software.amazon.awssdk.codegen.model.intermediate.Metadata; -import software.amazon.awssdk.codegen.model.intermediate.Protocol; import software.amazon.awssdk.codegen.model.intermediate.ShapeMarshaller; import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.codegen.model.intermediate.ShapeType; @@ -335,7 +334,7 @@ public static ShapeMarshaller createInputShapeMarshaller(ServiceMetadata service .withAction(operation.getName()) .withVerb(operation.getHttp().getMethod()) .withRequestUri(operation.getHttp().getRequestUri()) - .withSmithyProtocol(getSmithyProtocol(service.getProtocol())); + .withProtocol(service.getProtocol()); Input input = operation.getInput(); if (input != null) { marshaller.setLocationName(input.getLocationName()); @@ -354,12 +353,13 @@ public static ShapeMarshaller createInputShapeMarshaller(ServiceMetadata service } - private static String getSmithyProtocol(String protocol) { - switch (Protocol.fromValue(protocol)) { - case SMITHY_RPC_V2_CBOR: - return "rpc-v2-cbor"; - default: - return null; - } + /** + * Create the ShapeMarshaller to the input shape from the specified Operation. + * The input shape in the operation could be empty. + */ + public static ShapeMarshaller createSyntheticInputShapeMarshaller(ServiceMetadata service, Operation operation) { + ShapeMarshaller result = createInputShapeMarshaller(service, operation); + result.withIsSynthetic(true); + return result; } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java index 18d8d735908f..924e45d5b31d 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeMarshaller.java @@ -29,7 +29,9 @@ public class ShapeMarshaller { private String xmlNameSpaceUri; - private String smithyProtocol; + private Boolean isSynthetic = Boolean.FALSE; + + private String protocol; public String getAction() { return action; @@ -109,16 +111,29 @@ public ShapeMarshaller withXmlNameSpaceUri(String xmlNameSpaceUri) { return this; } - public String getSmithyProtocol() { - return smithyProtocol; + public Boolean getIsSynthetic() { + return isSynthetic; + } + + public void setIsSynthetic(Boolean isSynthetic) { + this.isSynthetic = isSynthetic; + } + + public ShapeMarshaller withIsSynthetic(Boolean isSynthetic) { + setIsSynthetic(isSynthetic); + return this; + } + + public String getProtocol() { + return protocol; } - public void setSmithyProtocol(String smithyProtocol) { - this.smithyProtocol = smithyProtocol; + public void setProtocol(String protocol) { + this.protocol = protocol; } - public ShapeMarshaller withSmithyProtocol(String smithyProtocol) { - setSmithyProtocol(smithyProtocol); + public ShapeMarshaller withProtocol(String protocol) { + setProtocol(protocol); return this; } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializer.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializer.java new file mode 100644 index 000000000000..035ffe059742 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializer.java @@ -0,0 +1,113 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.poet.transform.protocols; + +import com.squareup.javapoet.CodeBlock; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import software.amazon.awssdk.utils.MapUtils; + +/** + * Encapsulates the codegen serialization logic for the given value. + */ +public interface CodegenSerializer { + /** + * Creates a codegen serialization for the given value using the {@link CodeBlock.Builder}. + */ + void serialize(T value, CodeBlock.Builder builder); + + /** + * Codegen for String values. + */ + class CodegenStringSerializer implements CodegenSerializer { + + @Override + public void serialize(String value, CodeBlock.Builder builder) { + builder.add("$S", value); + } + } + + /** + * Codegen for literal values. + */ + class CodegenLiteralSerializer implements CodegenSerializer { + + @Override + public void serialize(Object value, CodeBlock.Builder builder) { + builder.add("$L", value); + } + } + + /** + * Codegen for List values. Serialized as {@code Arrays.asList(v0, ⋯, vn)}. + */ + class CodegenListSerializer implements CodegenSerializer> { + private final CodegenSerializerResolver resolver; + + public CodegenListSerializer(CodegenSerializerResolver resolver) { + this.resolver = resolver; + } + + @Override + public void serialize(List list, CodeBlock.Builder builder) { + builder.add("$T.asList(", Arrays.class); + boolean needsComma = false; + for (Object value : list) { + if (needsComma) { + builder.add(", "); + } + CodegenSerializer serializer = resolver.serializerFor(value); + serializer.serialize(value, builder); + needsComma = true; + } + builder.add(")"); + } + } + + + /** + * Codegen for Map values. Serialized as {@code MapUtils.of(k0, v0, ⋯, kn, vn)}. This only works for a small amount of + * key-value pairs, up to seven. + */ + class CodegenMapSerializer implements CodegenSerializer> { + private final CodegenSerializerResolver resolver; + + public CodegenMapSerializer(CodegenSerializerResolver resolver) { + this.resolver = resolver; + } + + @Override + public void serialize(Map map, CodeBlock.Builder builder) { + builder.add("$T.of(", MapUtils.class); + boolean needsComma = false; + for (Map.Entry kvp : map.entrySet()) { + if (needsComma) { + builder.add(", "); + } + Object key = kvp.getKey(); + CodegenSerializer keySerializer = resolver.serializerFor(key); + keySerializer.serialize(key, builder); + builder.add(", "); + Object value = kvp.getValue(); + CodegenSerializer valueSerializer = resolver.serializerFor(value); + valueSerializer.serialize(value, builder); + needsComma = true; + } + builder.add(")"); + } + } +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializerResolver.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializerResolver.java new file mode 100644 index 000000000000..51a49eb15b24 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/CodegenSerializerResolver.java @@ -0,0 +1,55 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.poet.transform.protocols; + +import java.util.List; +import java.util.Map; + +/** + * Resolves {@link CodegenSerializer} for a given instance. + */ +public interface CodegenSerializerResolver { + + CodegenSerializerResolver DEFAULT = new CodegenSerializerResolver() { + @Override + @SuppressWarnings("unchecked") + public CodegenSerializer serializerFor(T value) { + if (value == null) { + throw new NullPointerException("value"); + } + Class xclass = value.getClass(); + if (xclass == String.class) { + return (CodegenSerializer) new CodegenSerializer.CodegenStringSerializer(); + } + if (List.class.isAssignableFrom(xclass)) { + return (CodegenSerializer) new CodegenSerializer.CodegenListSerializer(this); + } + if (Map.class.isAssignableFrom(xclass)) { + return (CodegenSerializer) new CodegenSerializer.CodegenMapSerializer(this); + } + return (CodegenSerializer) new CodegenSerializer.CodegenLiteralSerializer(); + } + }; + + static CodegenSerializerResolver getDefault() { + return DEFAULT; + } + + /** + * Returns a proper codegen serializer for the given value. + */ + CodegenSerializer serializerFor(T value); +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java index c92ed28f67c6..322b9cf265ce 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java @@ -24,8 +24,12 @@ import com.squareup.javapoet.ParameterSpec; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import javax.lang.model.element.Modifier; +import software.amazon.awssdk.codegen.internal.ProtocolMetadataConstants; +import software.amazon.awssdk.codegen.internal.ProtocolMetadataDefault; +import software.amazon.awssdk.codegen.model.intermediate.Protocol; import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; @@ -99,17 +103,25 @@ protected FieldSpec operationInfoField() { .add(".hasImplicitPayloadMembers($L)", shapeModel.hasImplicitPayloadMembers()) .add(".hasPayloadMembers($L)", shapeModel.hasPayloadMembers()); + if (StringUtils.isNotBlank(shapeModel.getMarshaller().getTarget())) { initializationCodeBlockBuilder.add(".operationIdentifier($S)", shapeModel.getMarshaller().getTarget()); } - String smithyProtocol = shapeModel.getMarshaller().getSmithyProtocol(); - if (StringUtils.isNotBlank(smithyProtocol)) { - initializationCodeBlockBuilder.add(".putAdditionalMetadata($T.SMITHY_PROTOCOL, $S)", - OperationMetadataAttribute.class, smithyProtocol); + String protocol = shapeModel.getMarshaller().getProtocol(); + ProtocolMetadataConstants metadataConstants = ProtocolMetadataDefault.from(Protocol.fromValue(protocol)) + .protocolMetadata(shapeModel.getMarshaller()); + List, OperationMetadataAttribute>> keys = metadataConstants.keys(); + for (Map.Entry, OperationMetadataAttribute> kvp : keys) { + initializationCodeBlockBuilder.add(".putAdditionalMetadata($T.$L, ", + ClassName.get(kvp.getKey()), + fieldName(kvp.getKey(), kvp.getValue())); + Object value = metadataConstants.get(kvp.getValue()); + CodegenSerializer serializer = CodegenSerializerResolver.getDefault().serializerFor(value); + serializer.serialize(value, initializationCodeBlockBuilder); + initializationCodeBlockBuilder.add(")"); } - if (shapeModel.isHasStreamingMember()) { initializationCodeBlockBuilder.add(".hasStreamingInput(true)"); } @@ -125,4 +137,40 @@ protected FieldSpec operationInfoField() { .initializer(codeBlock) .build(); } + + + /** + * This method resolves a static reference to its name, for instance, when called with + *
+     * fieldName(AwsClientOption.class, AwsClientOption.AWS_REGION)
+     * 
+ * it will return the string "AWS_REGION" that we can use for codegen. Using the value directly avoid typo bugs and allows the + * compiler and the IDE to know about this relationship. + *

+ * This method uses the fully qualified names in the reflection package to avoid polluting this class imports. Adapted from + * https://stackoverflow.com/a/35416606 + */ + private static String fieldName(Class containingClass, Object fieldObject) { + java.lang.reflect.Field[] allFields = containingClass.getFields(); + for (java.lang.reflect.Field field : allFields) { + int modifiers = field.getModifiers(); + if (!java.lang.reflect.Modifier.isStatic(modifiers)) { + continue; + } + Object currentFieldObject; + try { + // For static fields you can pass a null to get back its value. + currentFieldObject = field.get(null); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + boolean isWantedField = fieldObject.equals(currentFieldObject); + if (isWantedField) { + return field.getName(); + } + } + throw new java.util.NoSuchElementException(String.format("cannot find constant %s in class %s", + fieldObject, + fieldObject.getClass().getName())); + } } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 0da4b4f3e902..2f63a78ba02b 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -39,6 +39,7 @@ import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.core.ExceptionMetadata; import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; import software.amazon.awssdk.protocols.core.ProtocolMarshaller; import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory; import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; @@ -51,6 +52,16 @@ @SdkProtectedApi public abstract class BaseAwsJsonProtocolFactory { + /** + * Used by operations that do not serialize the input, e.g., when the input is not defined in the model. RPCv2 uses it. + */ + public static final OperationMetadataAttribute USE_NO_OP_GENERATOR = new OperationMetadataAttribute<>(Boolean.class); + + /** + * Attribute for a protocol to configure extra headers for the operation. + */ + public static final OperationMetadataAttribute> HTTP_EXTRA_HEADERS = + OperationMetadataAttribute.forUnsafe(Map.class); /** * Content type resolver implementation for plain text AWS_JSON services. @@ -138,14 +149,15 @@ private MetricCollectingHttpResponseHandler timeUnmarshalling(HttpRespons } private StructuredJsonGenerator createGenerator(OperationInfo operationInfo) { - AwsJsonProtocol protocol = protocolMetadata.protocol(); - if (operationInfo.hasPayloadMembers() - || protocol == AwsJsonProtocol.AWS_JSON - || protocol == AwsJsonProtocol.SMITHY_RPC_V2_CBOR) { - return createGenerator(); - } else { + Boolean useNoOp = operationInfo.addtionalMetadata(USE_NO_OP_GENERATOR); + if (useNoOp == null) { + AwsJsonProtocol protocol = protocolMetadata.protocol(); + useNoOp = !operationInfo.hasPayloadMembers() && protocol != AwsJsonProtocol.AWS_JSON; + } + if (useNoOp) { return StructuredJsonGenerator.NO_OP; } + return createGenerator(); } @SdkTestInternalApi diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java index dc5f56e7ffbb..59122bc0b667 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java @@ -39,12 +39,12 @@ import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.protocols.core.InstantToString; import software.amazon.awssdk.protocols.core.OperationInfo; -import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; import software.amazon.awssdk.protocols.core.ProtocolMarshaller; import software.amazon.awssdk.protocols.core.ProtocolUtils; import software.amazon.awssdk.protocols.core.ValueToStringConverter.ValueToString; import software.amazon.awssdk.protocols.json.AwsJsonProtocol; import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; /** @@ -167,9 +167,9 @@ private SdkHttpFullRequest.Builder fillBasicRequestParams(OperationInfo operatio if (operationIdentifier != null) { requestBuilder.putHeader("X-Amz-Target", operationIdentifier); } - String smithyProtocol = operationInfo.addtionalMetadata(OperationMetadataAttribute.SMITHY_PROTOCOL); - if (smithyProtocol != null) { - requestBuilder.putHeader("smithy-protocol", smithyProtocol); + Map extraHeaders = operationInfo.addtionalMetadata(BaseAwsJsonProtocolFactory.HTTP_EXTRA_HEADERS); + if (extraHeaders != null) { + extraHeaders.forEach(requestBuilder::putHeader); } return requestBuilder; } diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java index b2a6e587dcdb..dc065ed36886 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/OperationMetadataAttribute.java @@ -27,13 +27,21 @@ @SdkProtectedApi public final class OperationMetadataAttribute extends AttributeMap.Key { - /** - * Attribute for configuring the smithy-protocol header. - */ - public static final OperationMetadataAttribute SMITHY_PROTOCOL = - new OperationMetadataAttribute<>(String.class); - public OperationMetadataAttribute(Class valueType) { super(valueType); } + + OperationMetadataAttribute(UnsafeValueType type) { + super(type); + } + + /** + * Useful for parameterized types. + * + * E.g., + * {@code OperationMetadataAttribute> KEY = forUnsafe(Map.class)} + */ + public static OperationMetadataAttribute forUnsafe(Class valueClass) { + return new OperationMetadataAttribute<>(new UnsafeValueType(valueClass)); + } } diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json index 62b74014c133..7f1c59d1fb94 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json @@ -529,7 +529,10 @@ "contains": { "Content-Type": "application/cbor", "smithy-protocol": "rpc-v2-cbor" - } + }, + "doesNotContain": [ + "X-Amz-Target" + ] } } } @@ -552,7 +555,36 @@ "contains": { "Content-Type": "application/cbor", "smithy-protocol": "rpc-v2-cbor" - } + }, + "doesNotContain": [ + "X-Amz-Target" + ] + } + } + } + }, + { + "description": "Body is empty and no Content-Type header if no input", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "NoInputOutput" + }, + "then": { + "serializedAs": { + "body": { + "encodedEquals": "" + }, + "headers": { + "contains": { + "smithy-protocol": "rpc-v2-cbor" + }, + "doesNotContain": [ + "Content-Type", + "X-Amz-Target" + ] } } } From 483e0063da6f4699a81a379df430ccf49149db14 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Tue, 20 Aug 2024 17:57:39 -0700 Subject: [PATCH 08/14] Add codgen tests (#5517) * Add codgen tests * Address PR comments * Address PR comments 2 * Add missing class rename * Add missing AWS_JSON protocol facts * Account for null protocol case --- .../internal/ProtocolMetadataDefault.java | 16 +- .../poet/client/specs/JsonProtocolSpec.java | 9 +- .../awssdk/codegen/poet/ClientTestModels.java | 11 + .../poet/client/AsyncClientClassTest.java | 7 + .../poet/client/SyncClientClassTest.java | 7 + .../TransformMarshallerSpecTest.java | 83 ++ .../client/c2j/rpcv2/customization.config | 2 + .../client/c2j/rpcv2/endpoint-rule-set.json | 2 + .../poet/client/c2j/rpcv2/endpoint-tests.json | 2 + .../poet/client/c2j/rpcv2/service-2.json | 546 ++++++++++ .../client/test-rpcv2-async-client-class.java | 959 ++++++++++++++++++ .../codegen/poet/client/test-rpcv2-sync.java | 822 +++++++++++++++ .../emptyinputoutputrequest-transformer.java | 42 + .../float16request-transformer.java | 43 + .../fractionalsecondsrequest-transformer.java | 43 + ...greetingwitherrorsrequest-transformer.java | 43 + .../noinputoutputrequest-transformer.java | 43 + ...rationwithdefaultsrequest-transformer.java | 42 + ...ptionalinputoutputrequest-transformer.java | 42 + .../recursiveshapesrequest-transformer.java | 42 + ...rpcv2cbordensemapsrequest-transformer.java | 42 + .../rpcv2cborlistsrequest-transformer.java | 42 + ...pcv2cborsparsemapsrequest-transformer.java | 42 + ...lescalarpropertiesrequest-transformer.java | 42 + ...arsenullsoperationrequest-transformer.java | 42 + .../json/BaseAwsJsonProtocolFactory.java | 11 +- .../protocols/json/internal/ProtocolFact.java | 107 ++ .../marshall/JsonProtocolMarshaller.java | 5 + 28 files changed, 3120 insertions(+), 19 deletions(-) create mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/transform/TransformMarshallerSpecTest.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/customization.config create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-rule-set.json create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-tests.json create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/service-2.json create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-async-client-class.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-sync.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/emptyinputoutputrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/float16request-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/fractionalsecondsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/greetingwitherrorsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/noinputoutputrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/operationwithdefaultsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/optionalinputoutputrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/recursiveshapesrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cbordensemapsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborlistsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborsparsemapsrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/simplescalarpropertiesrequest-transformer.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/sparsenullsoperationrequest-transformer.java create mode 100644 core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/ProtocolFact.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java index ca7c346bd19c..469565319726 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/internal/ProtocolMetadataDefault.java @@ -18,7 +18,6 @@ import software.amazon.awssdk.codegen.model.intermediate.Protocol; import software.amazon.awssdk.codegen.model.intermediate.ShapeMarshaller; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; -import software.amazon.awssdk.utils.MapUtils; /** * Enum that maps protocol to metadata attribute constants for a given operation. @@ -29,20 +28,17 @@ public enum ProtocolMetadataDefault { public ProtocolMetadataConstants protocolMetadata(ShapeMarshaller shapeMarshaller) { ProtocolMetadataConstants attributes = new DefaultProtocolMetadataConstants(); - // Smithy RPCv2 requires the header "smithy-protocol" with value "rpc-v2-cbor" - // See https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#requests. - attributes.put(BaseAwsJsonProtocolFactory.class, - BaseAwsJsonProtocolFactory.HTTP_EXTRA_HEADERS, - MapUtils.of("smithy-protocol", "rpc-v2-cbor")); - // If the shape is synthetic that means that no-input was defined in the model. For this // case the protocol requires to send an empty body with no content-type. See // https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#requests. // To accomplish this we use a no-op JSON generator. Otherwise, we serialize the input // even when no members are defined. - attributes.put(BaseAwsJsonProtocolFactory.class, - BaseAwsJsonProtocolFactory.USE_NO_OP_GENERATOR, - shapeMarshaller.getIsSynthetic()); + Boolean isSynthetic = shapeMarshaller.getIsSynthetic(); + if (Boolean.TRUE.equals(isSynthetic)) { + attributes.put(BaseAwsJsonProtocolFactory.class, + BaseAwsJsonProtocolFactory.GENERATES_BODY, + Boolean.FALSE); + } return attributes; } }, diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java index 6d2e174833ae..7907593c19b7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java @@ -97,10 +97,11 @@ public MethodSpec initProtocolFactory(IntermediateModel model) { .addCode("return builder\n") .addCode(".clientConfiguration(clientConfiguration)\n") .addCode(".defaultServiceExceptionSupplier($T::builder)\n", baseException) - .addCode(".protocol($T.$L)\n", AwsJsonProtocol.class, protocolEnumName(metadata.getProtocol())) - .addCode(".protocolVersion($S)\n", metadata.getJsonVersion()) - .addCode("$L", customErrorCodeFieldName()); - + .addCode(".protocol($T.$L)\n", AwsJsonProtocol.class, protocolEnumName(metadata.getProtocol())); + if (metadata.getJsonVersion() != null) { + methodSpec.addCode(".protocolVersion($S)\n", metadata.getJsonVersion()); + } + methodSpec.addCode("$L", customErrorCodeFieldName()); String contentType = Optional.ofNullable(model.getCustomizationConfig().getCustomServiceMetadata()) .map(MetadataConfig::getContentType) .orElse(metadata.getContentType()); diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java index d739b7ec5735..b48a4e9bc289 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java @@ -380,6 +380,17 @@ public static IntermediateModel internalConfigModels() { return new IntermediateModelBuilder(models).build(); } + public static IntermediateModel rpcv2ServiceModels() { + File serviceModel = new File(ClientTestModels.class.getResource("client/c2j/rpcv2/service-2.json").getFile()); + File customizationModel = new File(ClientTestModels.class.getResource("client/c2j/rpcv2/customization.config").getFile()); + C2jModels models = C2jModels.builder() + .serviceModel(getServiceModel(serviceModel)) + .customizationConfig(getCustomizationConfig(customizationModel)) + .build(); + + return new IntermediateModelBuilder(models).build(); + } + private static ServiceModel getServiceModel(File file) { return ModelLoaderUtils.loadModel(ServiceModel.class, file); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClassTest.java index fc9157feae18..ee5665c5a15e 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClassTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClassTest.java @@ -23,6 +23,7 @@ import static software.amazon.awssdk.codegen.poet.ClientTestModels.endpointDiscoveryModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.queryServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.restJsonServiceModels; +import static software.amazon.awssdk.codegen.poet.ClientTestModels.rpcv2ServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.xmlServiceModels; import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; @@ -92,6 +93,12 @@ public void asyncClientCustomPackageName() { assertThat(syncClientCustomServiceMetaData, generatesTo("test-custompackage-async.java")); } + @Test + public void asyncClientClassRpcv2() { + AsyncClientClass asyncClientClass = createAsyncClientClass(rpcv2ServiceModels(), true); + assertThat(asyncClientClass, generatesTo("test-rpcv2-async-client-class.java")); + } + private AsyncClientClass createAsyncClientClass(IntermediateModel model) { return new AsyncClientClass(GeneratorTaskParams.create(model, "sources/", "tests/", "resources/")); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/SyncClientClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/SyncClientClassTest.java index ebd088d143ec..2da02c594bc2 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/SyncClientClassTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/SyncClientClassTest.java @@ -22,6 +22,7 @@ import static software.amazon.awssdk.codegen.poet.ClientTestModels.endpointDiscoveryModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.queryServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.restJsonServiceModels; +import static software.amazon.awssdk.codegen.poet.ClientTestModels.rpcv2ServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.xmlServiceModels; import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; @@ -82,6 +83,12 @@ public void syncClientCustomPackageName() { assertThat(syncClientCustomServiceMetaData, generatesTo("test-custompackage-sync.java")); } + @Test + public void syncClientClassRpcV2() { + ClassSpec syncClientCustomServiceMetaData = createSyncClientClass(rpcv2ServiceModels(), true); + assertThat(syncClientCustomServiceMetaData, generatesTo("test-rpcv2-sync.java")); + } + private SyncClientClass createSyncClientClass(IntermediateModel model) { return new SyncClientClass(GeneratorTaskParams.create(model, "sources/", "tests/", "resources/")); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/transform/TransformMarshallerSpecTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/transform/TransformMarshallerSpecTest.java new file mode 100644 index 000000000000..5bb5184e9a34 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/transform/TransformMarshallerSpecTest.java @@ -0,0 +1,83 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.codegen.poet.transform; + +import static java.util.stream.Collectors.toList; +import static org.hamcrest.MatcherAssert.assertThat; +import static software.amazon.awssdk.codegen.poet.ClientTestModels.rpcv2ServiceModels; +import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; + +import java.util.Collection; +import java.util.Locale; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; + +public class TransformMarshallerSpecTest { + + @ParameterizedTest(name = "{index} - {0}") + @MethodSource("testCases") + public void runtCase(TestCase testCase) { + IntermediateModel model = testCase.model(); + model.getShapes().values().stream() + .filter(shape -> "Request".equals(shape.getType()) || shape.isEvent()) + .map(shape -> new Object[] {shape}).collect(toList()); + + String expectedFileName = String.format("%s/%s-transformer.java", + model.getMetadata().getProtocol().toString().toLowerCase(Locale.ENGLISH), + testCase.shapeModel().getShapeName().toLowerCase(Locale.ENGLISH)); + + assertThat(new MarshallerSpec(model, testCase.shapeModel()), generatesTo(expectedFileName)); + + } + + public static Collection testCases() { + IntermediateModel model = rpcv2ServiceModels(); + return + model.getShapes().values().stream() + .filter(shape -> "Request".equals(shape.getType()) || shape.isEvent()) + .map(s -> new TestCase(model, s)) + .collect(toList()); + } + + static class TestCase { + private final IntermediateModel model; + private final ShapeModel shapeModel; + + TestCase(IntermediateModel model, ShapeModel shapeModel) { + this.model = model; + this.shapeModel = shapeModel; + } + + public IntermediateModel model() { + return model; + } + + public ShapeModel shapeModel() { + return shapeModel; + } + + @Override + public String toString() { + return this.shapeModel.getShapeName(); + } + } + + public IntermediateModel getModel() { + return rpcv2ServiceModels(); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/customization.config b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/customization.config new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/customization.config @@ -0,0 +1,2 @@ +{ +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-rule-set.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-rule-set.json new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-rule-set.json @@ -0,0 +1,2 @@ +{ +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-tests.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-tests.json new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/endpoint-tests.json @@ -0,0 +1,2 @@ +{ +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/service-2.json b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/service-2.json new file mode 100644 index 000000000000..0cc5eeb51db6 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/rpcv2/service-2.json @@ -0,0 +1,546 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2023-03-10", + "auth":["aws.auth#sigv4"], + "endpointPrefix":"smithyrpcv2protocol", + "protocol":"smithy-rpc-v2-cbor", + "protocols":["smithy-rpc-v2-cbor"], + "serviceFullName":"RpcV2 Protocol Service", + "serviceId":"SmithyRpcV2Protocol", + "signatureVersion":"v4", + "signingName":"execute-api", + "targetPrefix":"RpcV2Protocol", + "uid":"smithy-rpcv2protocol-2023-03-10" + }, + "operations":{ + "EmptyInputOutput":{ + "name":"EmptyInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"EmptyStructure"}, + "output":{"shape":"EmptyStructure"} + }, + "Float16":{ + "name":"Float16", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"Float16Output"} + }, + "FractionalSeconds":{ + "name":"FractionalSeconds", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"FractionalSecondsOutput"} + }, + "GreetingWithErrors":{ + "name":"GreetingWithErrors", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "output":{"shape":"GreetingWithErrorsOutput"}, + "errors":[ + {"shape":"ComplexError"}, + {"shape":"InvalidGreeting"} + ], + "idempotent":true + }, + "NoInputOutput":{ + "name":"NoInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + } + }, + "OperationWithDefaults":{ + "name":"OperationWithDefaults", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"OperationWithDefaultsInput"}, + "output":{"shape":"OperationWithDefaultsOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "OptionalInputOutput":{ + "name":"OptionalInputOutput", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SimpleStructure"}, + "output":{"shape":"SimpleStructure"} + }, + "RecursiveShapes":{ + "name":"RecursiveShapes", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RecursiveShapesInputOutput"}, + "output":{"shape":"RecursiveShapesInputOutput"} + }, + "RpcV2CborDenseMaps":{ + "name":"RpcV2CborDenseMaps", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborDenseMapsInputOutput"}, + "output":{"shape":"RpcV2CborDenseMapsInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "RpcV2CborLists":{ + "name":"RpcV2CborLists", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborListInputOutput"}, + "output":{"shape":"RpcV2CborListInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ], + "idempotent":true + }, + "RpcV2CborSparseMaps":{ + "name":"RpcV2CborSparseMaps", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"RpcV2CborSparseMapsInputOutput"}, + "output":{"shape":"RpcV2CborSparseMapsInputOutput"}, + "errors":[ + {"shape":"ValidationException"} + ] + }, + "SimpleScalarProperties":{ + "name":"SimpleScalarProperties", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SimpleScalarStructure"}, + "output":{"shape":"SimpleScalarStructure"} + }, + "SparseNullsOperation":{ + "name":"SparseNullsOperation", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SparseNullsOperationInputOutput"}, + "output":{"shape":"SparseNullsOperationInputOutput"} + } + }, + "shapes":{ + "Blob":{"type":"blob"}, + "BlobList":{ + "type":"list", + "member":{"shape":"Blob"} + }, + "Boolean":{ + "type":"boolean", + "box":true + }, + "BooleanList":{ + "type":"list", + "member":{"shape":"Boolean"} + }, + "Byte":{ + "type":"byte", + "box":true + }, + "ClientOptionalDefaults":{ + "type":"structure", + "members":{ + "member":{"shape":"Integer"} + } + }, + "ComplexError":{ + "type":"structure", + "members":{ + "TopLevel":{"shape":"String"}, + "Nested":{"shape":"ComplexNestedErrorData"} + }, + "exception":true + }, + "ComplexNestedErrorData":{ + "type":"structure", + "members":{ + "Foo":{"shape":"String"} + } + }, + "DateTime":{ + "type":"timestamp" + }, + "Defaults":{ + "type":"structure", + "members":{ + "defaultString":{"shape":"String"}, + "defaultBoolean":{"shape":"Boolean"}, + "defaultList":{"shape":"TestStringList"}, + "defaultTimestamp":{"shape":"Timestamp"}, + "defaultBlob":{"shape":"Blob"}, + "defaultByte":{"shape":"Byte"}, + "defaultShort":{"shape":"Short"}, + "defaultInteger":{"shape":"Integer"}, + "defaultLong":{"shape":"Long"}, + "defaultFloat":{"shape":"Float"}, + "defaultDouble":{"shape":"Double"}, + "defaultMap":{"shape":"TestStringMap"}, + "defaultEnum":{"shape":"TestEnum"}, + "defaultIntEnum":{"shape":"TestIntEnum"}, + "emptyString":{"shape":"String"}, + "falseBoolean":{"shape":"Boolean"}, + "emptyBlob":{"shape":"Blob"}, + "zeroByte":{"shape":"Byte"}, + "zeroShort":{"shape":"Short"}, + "zeroInteger":{"shape":"Integer"}, + "zeroLong":{"shape":"Long"}, + "zeroFloat":{"shape":"Float"}, + "zeroDouble":{"shape":"Double"} + } + }, + "DenseBooleanMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Boolean"} + }, + "DenseNumberMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Integer"} + }, + "DenseSetMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"StringSet"} + }, + "DenseStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "DenseStructMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"GreetingStruct"} + }, + "Double":{ + "type":"double", + "box":true + }, + "EmptyStructure":{ + "type":"structure", + "members":{ + } + }, + "Float":{ + "type":"float", + "box":true + }, + "Float16Output":{ + "type":"structure", + "members":{ + "value":{"shape":"Double"} + } + }, + "FooEnum":{ + "type":"string", + "enum":[ + "Foo", + "Baz", + "Bar" + ] + }, + "FooEnumList":{ + "type":"list", + "member":{"shape":"FooEnum"} + }, + "FractionalSecondsOutput":{ + "type":"structure", + "members":{ + "datetime":{"shape":"DateTime"} + } + }, + "GreetingStruct":{ + "type":"structure", + "members":{ + "hi":{"shape":"String"} + } + }, + "GreetingWithErrorsOutput":{ + "type":"structure", + "members":{ + "greeting":{"shape":"String"} + } + }, + "Integer":{ + "type":"integer", + "box":true + }, + "IntegerEnum":{ + "type":"integer", + "box":true + }, + "IntegerEnumList":{ + "type":"list", + "member":{"shape":"IntegerEnum"} + }, + "IntegerList":{ + "type":"list", + "member":{"shape":"Integer"} + }, + "InvalidGreeting":{ + "type":"structure", + "members":{ + "Message":{"shape":"String"} + }, + "exception":true + }, + "Long":{ + "type":"long", + "box":true + }, + "NestedStringList":{ + "type":"list", + "member":{"shape":"StringList"} + }, + "OperationWithDefaultsInput":{ + "type":"structure", + "members":{ + "defaults":{"shape":"Defaults"}, + "clientOptionalDefaults":{"shape":"ClientOptionalDefaults"}, + "topLevelDefault":{"shape":"String"}, + "otherTopLevelDefault":{"shape":"Integer"} + } + }, + "OperationWithDefaultsOutput":{ + "type":"structure", + "members":{ + "defaultString":{"shape":"String"}, + "defaultBoolean":{"shape":"Boolean"}, + "defaultList":{"shape":"TestStringList"}, + "defaultTimestamp":{"shape":"Timestamp"}, + "defaultBlob":{"shape":"Blob"}, + "defaultByte":{"shape":"Byte"}, + "defaultShort":{"shape":"Short"}, + "defaultInteger":{"shape":"Integer"}, + "defaultLong":{"shape":"Long"}, + "defaultFloat":{"shape":"Float"}, + "defaultDouble":{"shape":"Double"}, + "defaultMap":{"shape":"TestStringMap"}, + "defaultEnum":{"shape":"TestEnum"}, + "defaultIntEnum":{"shape":"TestIntEnum"}, + "emptyString":{"shape":"String"}, + "falseBoolean":{"shape":"Boolean"}, + "emptyBlob":{"shape":"Blob"}, + "zeroByte":{"shape":"Byte"}, + "zeroShort":{"shape":"Short"}, + "zeroInteger":{"shape":"Integer"}, + "zeroLong":{"shape":"Long"}, + "zeroFloat":{"shape":"Float"}, + "zeroDouble":{"shape":"Double"} + } + }, + "RecursiveShapesInputOutput":{ + "type":"structure", + "members":{ + "nested":{"shape":"RecursiveShapesInputOutputNested1"} + } + }, + "RecursiveShapesInputOutputNested1":{ + "type":"structure", + "members":{ + "foo":{"shape":"String"}, + "nested":{"shape":"RecursiveShapesInputOutputNested2"} + } + }, + "RecursiveShapesInputOutputNested2":{ + "type":"structure", + "members":{ + "bar":{"shape":"String"}, + "recursiveMember":{"shape":"RecursiveShapesInputOutputNested1"} + } + }, + "RpcV2CborDenseMapsInputOutput":{ + "type":"structure", + "members":{ + "denseStructMap":{"shape":"DenseStructMap"}, + "denseNumberMap":{"shape":"DenseNumberMap"}, + "denseBooleanMap":{"shape":"DenseBooleanMap"}, + "denseStringMap":{"shape":"DenseStringMap"}, + "denseSetMap":{"shape":"DenseSetMap"} + } + }, + "RpcV2CborListInputOutput":{ + "type":"structure", + "members":{ + "stringList":{"shape":"StringList"}, + "stringSet":{"shape":"StringSet"}, + "integerList":{"shape":"IntegerList"}, + "booleanList":{"shape":"BooleanList"}, + "timestampList":{"shape":"TimestampList"}, + "enumList":{"shape":"FooEnumList"}, + "intEnumList":{"shape":"IntegerEnumList"}, + "nestedStringList":{"shape":"NestedStringList"}, + "structureList":{"shape":"StructureList"}, + "blobList":{"shape":"BlobList"} + } + }, + "RpcV2CborSparseMapsInputOutput":{ + "type":"structure", + "members":{ + "sparseStructMap":{"shape":"SparseStructMap"}, + "sparseNumberMap":{"shape":"SparseNumberMap"}, + "sparseBooleanMap":{"shape":"SparseBooleanMap"}, + "sparseStringMap":{"shape":"SparseStringMap"}, + "sparseSetMap":{"shape":"SparseSetMap"} + } + }, + "Short":{ + "type":"short", + "box":true + }, + "SimpleScalarStructure":{ + "type":"structure", + "members":{ + "trueBooleanValue":{"shape":"Boolean"}, + "falseBooleanValue":{"shape":"Boolean"}, + "byteValue":{"shape":"Byte"}, + "doubleValue":{"shape":"Double"}, + "floatValue":{"shape":"Float"}, + "integerValue":{"shape":"Integer"}, + "longValue":{"shape":"Long"}, + "shortValue":{"shape":"Short"}, + "stringValue":{"shape":"String"}, + "blobValue":{"shape":"Blob"} + } + }, + "SimpleStructure":{ + "type":"structure", + "members":{ + "value":{"shape":"String"} + } + }, + "SparseBooleanMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Boolean"} + }, + "SparseNullsOperationInputOutput":{ + "type":"structure", + "members":{ + "sparseStringList":{"shape":"SparseStringList"}, + "sparseStringMap":{"shape":"SparseStringMap"} + } + }, + "SparseNumberMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"Integer"} + }, + "SparseSetMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"StringSet"} + }, + "SparseStringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "SparseStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "SparseStructMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"GreetingStruct"} + }, + "String":{"type":"string"}, + "StringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "StringSet":{ + "type":"list", + "member":{"shape":"String"} + }, + "StructureList":{ + "type":"list", + "member":{"shape":"StructureListMember"} + }, + "StructureListMember":{ + "type":"structure", + "members":{ + "a":{"shape":"String"}, + "b":{"shape":"String"} + } + }, + "TestEnum":{ + "type":"string", + "enum":[ + "FOO", + "BAR", + "BAZ" + ] + }, + "TestIntEnum":{ + "type":"integer", + "box":true + }, + "TestStringList":{ + "type":"list", + "member":{"shape":"String"} + }, + "TestStringMap":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"} + }, + "Timestamp":{"type":"timestamp"}, + "TimestampList":{ + "type":"list", + "member":{"shape":"Timestamp"} + }, + "ValidationException":{ + "type":"structure", + "required":["message"], + "members":{ + "message":{"shape":"String"}, + "fieldList":{"shape":"ValidationExceptionFieldList"} + }, + "exception":true + }, + "ValidationExceptionField":{ + "type":"structure", + "required":[ + "path", + "message" + ], + "members":{ + "path":{"shape":"String"}, + "message":{"shape":"String"} + } + }, + "ValidationExceptionFieldList":{ + "type":"list", + "member":{"shape":"ValidationExceptionField"} + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-async-client-class.java new file mode 100644 index 000000000000..b182b7e56b24 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-async-client-class.java @@ -0,0 +1,959 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol; + +import static software.amazon.awssdk.utils.FunctionalUtils.runAndLogError; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.client.handler.AwsAsyncClientHandler; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.awscore.internal.AwsProtocolMetadata; +import software.amazon.awssdk.awscore.internal.AwsServiceProtocol; +import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.RequestOverrideConfiguration; +import software.amazon.awssdk.core.SdkPlugin; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.client.handler.AsyncClientHandler; +import software.amazon.awssdk.core.client.handler.ClientExecutionParams; +import software.amazon.awssdk.core.http.HttpResponseHandler; +import software.amazon.awssdk.core.metrics.CoreMetric; +import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; +import software.amazon.awssdk.metrics.NoOpMetricCollector; +import software.amazon.awssdk.protocols.core.ExceptionMetadata; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.protocols.json.JsonOperationMetadata; +import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; +import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.services.smithyrpcv2protocol.internal.SmithyRpcV2ProtocolServiceClientConfigurationBuilder; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.ComplexErrorException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.EmptyInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.EmptyInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.Float16Request; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.Float16Response; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.FractionalSecondsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.FractionalSecondsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.GreetingWithErrorsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.GreetingWithErrorsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.InvalidGreetingException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.NoInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.NoInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OperationWithDefaultsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OperationWithDefaultsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OptionalInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OptionalInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RecursiveShapesRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RecursiveShapesResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborDenseMapsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborDenseMapsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborListsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborListsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborSparseMapsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborSparseMapsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SimpleScalarPropertiesRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SimpleScalarPropertiesResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SmithyRpcV2ProtocolException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SparseNullsOperationRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SparseNullsOperationResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.ValidationException; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.EmptyInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.Float16RequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.FractionalSecondsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.GreetingWithErrorsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.NoInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.OperationWithDefaultsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.OptionalInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RecursiveShapesRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborDenseMapsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborListsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborSparseMapsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.SimpleScalarPropertiesRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.SparseNullsOperationRequestMarshaller; +import software.amazon.awssdk.utils.CompletableFutureUtils; + +/** + * Internal implementation of {@link SmithyRpcV2ProtocolAsyncClient}. + * + * @see SmithyRpcV2ProtocolAsyncClient#builder() + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +final class DefaultSmithyRpcV2ProtocolAsyncClient implements SmithyRpcV2ProtocolAsyncClient { + private static final Logger log = LoggerFactory.getLogger(DefaultSmithyRpcV2ProtocolAsyncClient.class); + + private static final AwsProtocolMetadata protocolMetadata = AwsProtocolMetadata.builder() + .serviceProtocol(AwsServiceProtocol.SMITHY_RPC_V2_CBOR).build(); + + private final AsyncClientHandler clientHandler; + + private final SmithyRpcV2CborProtocolFactory protocolFactory; + + private final SdkClientConfiguration clientConfiguration; + + protected DefaultSmithyRpcV2ProtocolAsyncClient(SdkClientConfiguration clientConfiguration) { + this.clientHandler = new AwsAsyncClientHandler(clientConfiguration); + this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build(); + this.protocolFactory = init(SmithyRpcV2CborProtocolFactory.builder()).build(); + } + + /** + * Invokes the EmptyInputOutput operation asynchronously. + * + * @param emptyInputOutputRequest + * @return A Java Future containing the result of the EmptyInputOutput operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *

    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.EmptyInputOutput + * @see AWS API Documentation + */ + @Override + public CompletableFuture emptyInputOutput(EmptyInputOutputRequest emptyInputOutputRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(emptyInputOutputRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, emptyInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "EmptyInputOutput"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, EmptyInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("EmptyInputOutput").withProtocolMetadata(protocolMetadata) + .withMarshaller(new EmptyInputOutputRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(emptyInputOutputRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the Float16 operation asynchronously. + * + * @param float16Request + * @return A Java Future containing the result of the Float16 operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.Float16 + * @see AWS + * API Documentation + */ + @Override + public CompletableFuture float16(Float16Request float16Request) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(float16Request, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, float16Request + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "Float16"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + Float16Response::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams().withOperationName("Float16") + .withProtocolMetadata(protocolMetadata).withMarshaller(new Float16RequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(float16Request)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the FractionalSeconds operation asynchronously. + * + * @param fractionalSecondsRequest + * @return A Java Future containing the result of the FractionalSeconds operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.FractionalSeconds + * @see AWS API Documentation + */ + @Override + public CompletableFuture fractionalSeconds(FractionalSecondsRequest fractionalSecondsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(fractionalSecondsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, fractionalSecondsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "FractionalSeconds"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, FractionalSecondsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("FractionalSeconds").withProtocolMetadata(protocolMetadata) + .withMarshaller(new FractionalSecondsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(fractionalSecondsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the GreetingWithErrors operation asynchronously. + * + * @param greetingWithErrorsRequest + * @return A Java Future containing the result of the GreetingWithErrors operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • ComplexErrorException
  • + *
  • InvalidGreetingException
  • + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.GreetingWithErrors + * @see AWS API Documentation + */ + @Override + public CompletableFuture greetingWithErrors(GreetingWithErrorsRequest greetingWithErrorsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(greetingWithErrorsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, greetingWithErrorsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "GreetingWithErrors"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, GreetingWithErrorsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("GreetingWithErrors").withProtocolMetadata(protocolMetadata) + .withMarshaller(new GreetingWithErrorsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(greetingWithErrorsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the NoInputOutput operation asynchronously. + * + * @param noInputOutputRequest + * @return A Java Future containing the result of the NoInputOutput operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.NoInputOutput + * @see AWS API Documentation + */ + @Override + public CompletableFuture noInputOutput(NoInputOutputRequest noInputOutputRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(noInputOutputRequest, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, noInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "NoInputOutput"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + NoInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("NoInputOutput").withProtocolMetadata(protocolMetadata) + .withMarshaller(new NoInputOutputRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(noInputOutputRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the OperationWithDefaults operation asynchronously. + * + * @param operationWithDefaultsRequest + * @return A Java Future containing the result of the OperationWithDefaults operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • ValidationException
  • + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.OperationWithDefaults + * @see AWS API Documentation + */ + @Override + public CompletableFuture operationWithDefaults( + OperationWithDefaultsRequest operationWithDefaultsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(operationWithDefaultsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithDefaultsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithDefaults"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, OperationWithDefaultsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OperationWithDefaults").withProtocolMetadata(protocolMetadata) + .withMarshaller(new OperationWithDefaultsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(operationWithDefaultsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the OptionalInputOutput operation asynchronously. + * + * @param optionalInputOutputRequest + * @return A Java Future containing the result of the OptionalInputOutput operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.OptionalInputOutput + * @see AWS API Documentation + */ + @Override + public CompletableFuture optionalInputOutput( + OptionalInputOutputRequest optionalInputOutputRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(optionalInputOutputRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, optionalInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OptionalInputOutput"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, OptionalInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("OptionalInputOutput").withProtocolMetadata(protocolMetadata) + .withMarshaller(new OptionalInputOutputRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(optionalInputOutputRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the RecursiveShapes operation asynchronously. + * + * @param recursiveShapesRequest + * @return A Java Future containing the result of the RecursiveShapes operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.RecursiveShapes + * @see AWS API Documentation + */ + @Override + public CompletableFuture recursiveShapes(RecursiveShapesRequest recursiveShapesRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(recursiveShapesRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, recursiveShapesRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RecursiveShapes"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RecursiveShapesResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("RecursiveShapes").withProtocolMetadata(protocolMetadata) + .withMarshaller(new RecursiveShapesRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(recursiveShapesRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the RpcV2CborDenseMaps operation asynchronously. + * + * @param rpcV2CborDenseMapsRequest + * @return A Java Future containing the result of the RpcV2CborDenseMaps operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • ValidationException
  • + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.RpcV2CborDenseMaps + * @see AWS API Documentation + */ + @Override + public CompletableFuture rpcV2CborDenseMaps(RpcV2CborDenseMapsRequest rpcV2CborDenseMapsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborDenseMapsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborDenseMapsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborDenseMaps"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RpcV2CborDenseMapsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("RpcV2CborDenseMaps").withProtocolMetadata(protocolMetadata) + .withMarshaller(new RpcV2CborDenseMapsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(rpcV2CborDenseMapsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the RpcV2CborLists operation asynchronously. + * + * @param rpcV2CborListsRequest + * @return A Java Future containing the result of the RpcV2CborLists operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • ValidationException
  • + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.RpcV2CborLists + * @see AWS API Documentation + */ + @Override + public CompletableFuture rpcV2CborLists(RpcV2CborListsRequest rpcV2CborListsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborListsRequest, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborListsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborLists"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RpcV2CborListsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("RpcV2CborLists").withProtocolMetadata(protocolMetadata) + .withMarshaller(new RpcV2CborListsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(rpcV2CborListsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the RpcV2CborSparseMaps operation asynchronously. + * + * @param rpcV2CborSparseMapsRequest + * @return A Java Future containing the result of the RpcV2CborSparseMaps operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • ValidationException
  • + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.RpcV2CborSparseMaps + * @see AWS API Documentation + */ + @Override + public CompletableFuture rpcV2CborSparseMaps( + RpcV2CborSparseMapsRequest rpcV2CborSparseMapsRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborSparseMapsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborSparseMapsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborSparseMaps"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RpcV2CborSparseMapsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("RpcV2CborSparseMaps").withProtocolMetadata(protocolMetadata) + .withMarshaller(new RpcV2CborSparseMapsRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(rpcV2CborSparseMapsRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the SimpleScalarProperties operation asynchronously. + * + * @param simpleScalarPropertiesRequest + * @return A Java Future containing the result of the SimpleScalarProperties operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.SimpleScalarProperties + * @see AWS API Documentation + */ + @Override + public CompletableFuture simpleScalarProperties( + SimpleScalarPropertiesRequest simpleScalarPropertiesRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(simpleScalarPropertiesRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, simpleScalarPropertiesRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "SimpleScalarProperties"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, SimpleScalarPropertiesResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("SimpleScalarProperties").withProtocolMetadata(protocolMetadata) + .withMarshaller(new SimpleScalarPropertiesRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(simpleScalarPropertiesRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + /** + * Invokes the SparseNullsOperation operation asynchronously. + * + * @param sparseNullsOperationRequest + * @return A Java Future containing the result of the SparseNullsOperation operation returned by the service.
+ * The CompletableFuture returned by this method can be completed exceptionally with the following + * exceptions. The exception returned is wrapped with CompletionException, so you need to invoke + * {@link Throwable#getCause} to retrieve the underlying exception. + *
    + *
  • SdkException Base class for all exceptions that can be thrown by the SDK (both service and client). + * Can be used for catch all scenarios.
  • + *
  • SdkClientException If any client side error occurs such as an IO related failure, failure to get + * credentials, etc.
  • + *
  • SmithyRpcV2ProtocolException Base class for all service exceptions. Unknown exceptions will be thrown + * as an instance of this type.
  • + *
+ * @sample SmithyRpcV2ProtocolAsyncClient.SparseNullsOperation + * @see AWS API Documentation + */ + @Override + public CompletableFuture sparseNullsOperation( + SparseNullsOperationRequest sparseNullsOperationRequest) { + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(sparseNullsOperationRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, sparseNullsOperationRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "SparseNullsOperation"); + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, SparseNullsOperationResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + + CompletableFuture executeFuture = clientHandler + .execute(new ClientExecutionParams() + .withOperationName("SparseNullsOperation").withProtocolMetadata(protocolMetadata) + .withMarshaller(new SparseNullsOperationRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withMetricCollector(apiCallMetricCollector) + .withInput(sparseNullsOperationRequest)); + CompletableFuture whenCompleted = executeFuture.whenComplete((r, e) -> { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + }); + executeFuture = CompletableFutureUtils.forwardExceptionTo(whenCompleted, executeFuture); + return executeFuture; + } catch (Throwable t) { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + return CompletableFutureUtils.failedFuture(t); + } + } + + @Override + public final SmithyRpcV2ProtocolServiceClientConfiguration serviceClientConfiguration() { + return new SmithyRpcV2ProtocolServiceClientConfigurationBuilder(this.clientConfiguration.toBuilder()).build(); + } + + @Override + public final String serviceName() { + return SERVICE_NAME; + } + + private > T init(T builder) { + return builder + .clientConfiguration(clientConfiguration) + .defaultServiceExceptionSupplier(SmithyRpcV2ProtocolException::builder) + .protocol(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) + .protocolVersion("1.1") + .registerModeledException( + ExceptionMetadata.builder().errorCode("ValidationException") + .exceptionBuilderSupplier(ValidationException::builder).build()) + .registerModeledException( + ExceptionMetadata.builder().errorCode("InvalidGreeting") + .exceptionBuilderSupplier(InvalidGreetingException::builder).build()) + .registerModeledException( + ExceptionMetadata.builder().errorCode("ComplexError") + .exceptionBuilderSupplier(ComplexErrorException::builder).build()); + } + + private static List resolveMetricPublishers(SdkClientConfiguration clientConfiguration, + RequestOverrideConfiguration requestOverrideConfiguration) { + List publishers = null; + if (requestOverrideConfiguration != null) { + publishers = requestOverrideConfiguration.metricPublishers(); + } + if (publishers == null || publishers.isEmpty()) { + publishers = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHERS); + } + if (publishers == null) { + publishers = Collections.emptyList(); + } + return publishers; + } + + private void updateRetryStrategyClientConfiguration(SdkClientConfiguration.Builder configuration) { + ClientOverrideConfiguration.Builder builder = configuration.asOverrideConfigurationBuilder(); + RetryMode retryMode = builder.retryMode(); + if (retryMode != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, AwsRetryStrategy.forRetryMode(retryMode)); + } else { + Consumer> configurator = builder.retryStrategyConfigurator(); + if (configurator != null) { + RetryStrategy.Builder defaultBuilder = AwsRetryStrategy.defaultRetryStrategy().toBuilder(); + configurator.accept(defaultBuilder); + configuration.option(SdkClientOption.RETRY_STRATEGY, defaultBuilder.build()); + } else { + RetryStrategy retryStrategy = builder.retryStrategy(); + if (retryStrategy != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, retryStrategy); + } + } + } + configuration.option(SdkClientOption.CONFIGURED_RETRY_MODE, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_STRATEGY, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_CONFIGURATOR, null); + } + + private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, SdkClientConfiguration clientConfiguration) { + List plugins = request.overrideConfiguration().map(c -> c.plugins()).orElse(Collections.emptyList()); + SdkClientConfiguration.Builder configuration = clientConfiguration.toBuilder(); + if (plugins.isEmpty()) { + return configuration.build(); + } + SmithyRpcV2ProtocolServiceClientConfigurationBuilder serviceConfigBuilder = new SmithyRpcV2ProtocolServiceClientConfigurationBuilder( + configuration); + for (SdkPlugin plugin : plugins) { + plugin.configureClient(serviceConfigBuilder); + } + updateRetryStrategyClientConfiguration(configuration); + return configuration.build(); + } + + private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, + JsonOperationMetadata operationMetadata) { + return protocolFactory.createErrorResponseHandler(operationMetadata); + } + + @Override + public void close() { + clientHandler.close(); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-sync.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-sync.java new file mode 100644 index 000000000000..c02466218908 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-rpcv2-sync.java @@ -0,0 +1,822 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.awscore.internal.AwsProtocolMetadata; +import software.amazon.awssdk.awscore.internal.AwsServiceProtocol; +import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.RequestOverrideConfiguration; +import software.amazon.awssdk.core.SdkPlugin; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.client.handler.ClientExecutionParams; +import software.amazon.awssdk.core.client.handler.SyncClientHandler; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.http.HttpResponseHandler; +import software.amazon.awssdk.core.metrics.CoreMetric; +import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; +import software.amazon.awssdk.metrics.NoOpMetricCollector; +import software.amazon.awssdk.protocols.core.ExceptionMetadata; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.protocols.json.JsonOperationMetadata; +import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; +import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.services.smithyrpcv2protocol.internal.SmithyRpcV2ProtocolServiceClientConfigurationBuilder; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.ComplexErrorException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.EmptyInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.EmptyInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.Float16Request; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.Float16Response; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.FractionalSecondsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.FractionalSecondsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.GreetingWithErrorsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.GreetingWithErrorsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.InvalidGreetingException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.NoInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.NoInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OperationWithDefaultsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OperationWithDefaultsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OptionalInputOutputRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OptionalInputOutputResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RecursiveShapesRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RecursiveShapesResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborDenseMapsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborDenseMapsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborListsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborListsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborSparseMapsRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborSparseMapsResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SimpleScalarPropertiesRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SimpleScalarPropertiesResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SmithyRpcV2ProtocolException; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SparseNullsOperationRequest; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SparseNullsOperationResponse; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.ValidationException; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.EmptyInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.Float16RequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.FractionalSecondsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.GreetingWithErrorsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.NoInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.OperationWithDefaultsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.OptionalInputOutputRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RecursiveShapesRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborDenseMapsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborListsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.RpcV2CborSparseMapsRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.SimpleScalarPropertiesRequestMarshaller; +import software.amazon.awssdk.services.smithyrpcv2protocol.transform.SparseNullsOperationRequestMarshaller; +import software.amazon.awssdk.utils.Logger; + +/** + * Internal implementation of {@link SmithyRpcV2ProtocolClient}. + * + * @see SmithyRpcV2ProtocolClient#builder() + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +final class DefaultSmithyRpcV2ProtocolClient implements SmithyRpcV2ProtocolClient { + private static final Logger log = Logger.loggerFor(DefaultSmithyRpcV2ProtocolClient.class); + + private static final AwsProtocolMetadata protocolMetadata = AwsProtocolMetadata.builder() + .serviceProtocol(AwsServiceProtocol.SMITHY_RPC_V2_CBOR).build(); + + private final SyncClientHandler clientHandler; + + private final SmithyRpcV2CborProtocolFactory protocolFactory; + + private final SdkClientConfiguration clientConfiguration; + + protected DefaultSmithyRpcV2ProtocolClient(SdkClientConfiguration clientConfiguration) { + this.clientHandler = new AwsSyncClientHandler(clientConfiguration); + this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build(); + this.protocolFactory = init(SmithyRpcV2CborProtocolFactory.builder()).build(); + } + + /** + * Invokes the EmptyInputOutput operation. + * + * @param emptyInputOutputRequest + * @return Result of the EmptyInputOutput operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.EmptyInputOutput + * @see AWS API Documentation + */ + @Override + public EmptyInputOutputResponse emptyInputOutput(EmptyInputOutputRequest emptyInputOutputRequest) throws AwsServiceException, + SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + EmptyInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(emptyInputOutputRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, emptyInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "EmptyInputOutput"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("EmptyInputOutput").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(emptyInputOutputRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new EmptyInputOutputRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the Float16 operation. + * + * @param float16Request + * @return Result of the Float16 operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.Float16 + * @see AWS + * API Documentation + */ + @Override + public Float16Response float16(Float16Request float16Request) throws AwsServiceException, SdkClientException, + SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + Float16Response::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(float16Request, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, float16Request + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "Float16"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("Float16").withProtocolMetadata(protocolMetadata).withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withRequestConfiguration(clientConfiguration) + .withInput(float16Request).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new Float16RequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the FractionalSeconds operation. + * + * @param fractionalSecondsRequest + * @return Result of the FractionalSeconds operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.FractionalSeconds + * @see AWS API Documentation + */ + @Override + public FractionalSecondsResponse fractionalSeconds(FractionalSecondsRequest fractionalSecondsRequest) + throws AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + FractionalSecondsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(fractionalSecondsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, fractionalSecondsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "FractionalSeconds"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("FractionalSeconds").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(fractionalSecondsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new FractionalSecondsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the GreetingWithErrors operation. + * + * @param greetingWithErrorsRequest + * @return Result of the GreetingWithErrors operation returned by the service. + * @throws ComplexErrorException + * @throws InvalidGreetingException + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.GreetingWithErrors + * @see AWS API Documentation + */ + @Override + public GreetingWithErrorsResponse greetingWithErrors(GreetingWithErrorsRequest greetingWithErrorsRequest) + throws ComplexErrorException, InvalidGreetingException, AwsServiceException, SdkClientException, + SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, GreetingWithErrorsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(greetingWithErrorsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, greetingWithErrorsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "GreetingWithErrors"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("GreetingWithErrors").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(greetingWithErrorsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new GreetingWithErrorsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the NoInputOutput operation. + * + * @param noInputOutputRequest + * @return Result of the NoInputOutput operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.NoInputOutput + * @see AWS API Documentation + */ + @Override + public NoInputOutputResponse noInputOutput(NoInputOutputRequest noInputOutputRequest) throws AwsServiceException, + SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + NoInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(noInputOutputRequest, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, noInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "NoInputOutput"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("NoInputOutput").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(noInputOutputRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new NoInputOutputRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the OperationWithDefaults operation. + * + * @param operationWithDefaultsRequest + * @return Result of the OperationWithDefaults operation returned by the service. + * @throws ValidationException + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.OperationWithDefaults + * @see AWS API Documentation + */ + @Override + public OperationWithDefaultsResponse operationWithDefaults(OperationWithDefaultsRequest operationWithDefaultsRequest) + throws ValidationException, AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, OperationWithDefaultsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(operationWithDefaultsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, operationWithDefaultsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OperationWithDefaults"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("OperationWithDefaults").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(operationWithDefaultsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new OperationWithDefaultsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the OptionalInputOutput operation. + * + * @param optionalInputOutputRequest + * @return Result of the OptionalInputOutput operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.OptionalInputOutput + * @see AWS API Documentation + */ + @Override + public OptionalInputOutputResponse optionalInputOutput(OptionalInputOutputRequest optionalInputOutputRequest) + throws AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, OptionalInputOutputResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(optionalInputOutputRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, optionalInputOutputRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "OptionalInputOutput"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("OptionalInputOutput").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(optionalInputOutputRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new OptionalInputOutputRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the RecursiveShapes operation. + * + * @param recursiveShapesRequest + * @return Result of the RecursiveShapes operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.RecursiveShapes + * @see AWS API Documentation + */ + @Override + public RecursiveShapesResponse recursiveShapes(RecursiveShapesRequest recursiveShapesRequest) throws AwsServiceException, + SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + RecursiveShapesResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(recursiveShapesRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, recursiveShapesRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RecursiveShapes"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("RecursiveShapes").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(recursiveShapesRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new RecursiveShapesRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the RpcV2CborDenseMaps operation. + * + * @param rpcV2CborDenseMapsRequest + * @return Result of the RpcV2CborDenseMaps operation returned by the service. + * @throws ValidationException + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.RpcV2CborDenseMaps + * @see AWS API Documentation + */ + @Override + public RpcV2CborDenseMapsResponse rpcV2CborDenseMaps(RpcV2CborDenseMapsRequest rpcV2CborDenseMapsRequest) + throws ValidationException, AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RpcV2CborDenseMapsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborDenseMapsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborDenseMapsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborDenseMaps"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("RpcV2CborDenseMaps").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(rpcV2CborDenseMapsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new RpcV2CborDenseMapsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the RpcV2CborLists operation. + * + * @param rpcV2CborListsRequest + * @return Result of the RpcV2CborLists operation returned by the service. + * @throws ValidationException + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.RpcV2CborLists + * @see AWS API Documentation + */ + @Override + public RpcV2CborListsResponse rpcV2CborLists(RpcV2CborListsRequest rpcV2CborListsRequest) throws ValidationException, + AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, + RpcV2CborListsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborListsRequest, this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborListsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborLists"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("RpcV2CborLists").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(rpcV2CborListsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new RpcV2CborListsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the RpcV2CborSparseMaps operation. + * + * @param rpcV2CborSparseMapsRequest + * @return Result of the RpcV2CborSparseMaps operation returned by the service. + * @throws ValidationException + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.RpcV2CborSparseMaps + * @see AWS API Documentation + */ + @Override + public RpcV2CborSparseMapsResponse rpcV2CborSparseMaps(RpcV2CborSparseMapsRequest rpcV2CborSparseMapsRequest) + throws ValidationException, AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, RpcV2CborSparseMapsResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(rpcV2CborSparseMapsRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, rpcV2CborSparseMapsRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "RpcV2CborSparseMaps"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("RpcV2CborSparseMaps").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(rpcV2CborSparseMapsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new RpcV2CborSparseMapsRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the SimpleScalarProperties operation. + * + * @param simpleScalarPropertiesRequest + * @return Result of the SimpleScalarProperties operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.SimpleScalarProperties + * @see AWS API Documentation + */ + @Override + public SimpleScalarPropertiesResponse simpleScalarProperties(SimpleScalarPropertiesRequest simpleScalarPropertiesRequest) + throws AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, SimpleScalarPropertiesResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(simpleScalarPropertiesRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, simpleScalarPropertiesRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "SimpleScalarProperties"); + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("SimpleScalarProperties").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(simpleScalarPropertiesRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new SimpleScalarPropertiesRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + /** + * Invokes the SparseNullsOperation operation. + * + * @param sparseNullsOperationRequest + * @return Result of the SparseNullsOperation operation returned by the service. + * @throws SdkException + * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for + * catch all scenarios. + * @throws SdkClientException + * If any client side error occurs such as an IO related failure, failure to get credentials, etc. + * @throws SmithyRpcV2ProtocolException + * Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. + * @sample SmithyRpcV2ProtocolClient.SparseNullsOperation + * @see AWS API Documentation + */ + @Override + public SparseNullsOperationResponse sparseNullsOperation(SparseNullsOperationRequest sparseNullsOperationRequest) + throws AwsServiceException, SdkClientException, SmithyRpcV2ProtocolException { + JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) + .isPayloadJson(true).build(); + + HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( + operationMetadata, SparseNullsOperationResponse::builder); + + HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, + operationMetadata); + SdkClientConfiguration clientConfiguration = updateSdkClientConfiguration(sparseNullsOperationRequest, + this.clientConfiguration); + List metricPublishers = resolveMetricPublishers(clientConfiguration, sparseNullsOperationRequest + .overrideConfiguration().orElse(null)); + MetricCollector apiCallMetricCollector = metricPublishers.isEmpty() ? NoOpMetricCollector.create() : MetricCollector + .create("ApiCall"); + try { + apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "SmithyRpcV2Protocol"); + apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "SparseNullsOperation"); + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("SparseNullsOperation").withProtocolMetadata(protocolMetadata) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withRequestConfiguration(clientConfiguration).withInput(sparseNullsOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new SparseNullsOperationRequestMarshaller(protocolFactory))); + } finally { + metricPublishers.forEach(p -> p.publish(apiCallMetricCollector.collect())); + } + } + + @Override + public final String serviceName() { + return SERVICE_NAME; + } + + private static List resolveMetricPublishers(SdkClientConfiguration clientConfiguration, + RequestOverrideConfiguration requestOverrideConfiguration) { + List publishers = null; + if (requestOverrideConfiguration != null) { + publishers = requestOverrideConfiguration.metricPublishers(); + } + if (publishers == null || publishers.isEmpty()) { + publishers = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHERS); + } + if (publishers == null) { + publishers = Collections.emptyList(); + } + return publishers; + } + + private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, + JsonOperationMetadata operationMetadata) { + return protocolFactory.createErrorResponseHandler(operationMetadata); + } + + private void updateRetryStrategyClientConfiguration(SdkClientConfiguration.Builder configuration) { + ClientOverrideConfiguration.Builder builder = configuration.asOverrideConfigurationBuilder(); + RetryMode retryMode = builder.retryMode(); + if (retryMode != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, AwsRetryStrategy.forRetryMode(retryMode)); + } else { + Consumer> configurator = builder.retryStrategyConfigurator(); + if (configurator != null) { + RetryStrategy.Builder defaultBuilder = AwsRetryStrategy.defaultRetryStrategy().toBuilder(); + configurator.accept(defaultBuilder); + configuration.option(SdkClientOption.RETRY_STRATEGY, defaultBuilder.build()); + } else { + RetryStrategy retryStrategy = builder.retryStrategy(); + if (retryStrategy != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, retryStrategy); + } + } + } + configuration.option(SdkClientOption.CONFIGURED_RETRY_MODE, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_STRATEGY, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_CONFIGURATOR, null); + } + + private SdkClientConfiguration updateSdkClientConfiguration(SdkRequest request, SdkClientConfiguration clientConfiguration) { + List plugins = request.overrideConfiguration().map(c -> c.plugins()).orElse(Collections.emptyList()); + SdkClientConfiguration.Builder configuration = clientConfiguration.toBuilder(); + if (plugins.isEmpty()) { + return configuration.build(); + } + SmithyRpcV2ProtocolServiceClientConfigurationBuilder serviceConfigBuilder = new SmithyRpcV2ProtocolServiceClientConfigurationBuilder( + configuration); + for (SdkPlugin plugin : plugins) { + plugin.configureClient(serviceConfigBuilder); + } + updateRetryStrategyClientConfiguration(configuration); + return configuration.build(); + } + + private > T init(T builder) { + return builder + .clientConfiguration(clientConfiguration) + .defaultServiceExceptionSupplier(SmithyRpcV2ProtocolException::builder) + .protocol(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) + .protocolVersion("1.1") + .registerModeledException( + ExceptionMetadata.builder().errorCode("ValidationException") + .exceptionBuilderSupplier(ValidationException::builder).build()) + .registerModeledException( + ExceptionMetadata.builder().errorCode("InvalidGreeting") + .exceptionBuilderSupplier(InvalidGreetingException::builder).build()) + .registerModeledException( + ExceptionMetadata.builder().errorCode("ComplexError") + .exceptionBuilderSupplier(ComplexErrorException::builder).build()); + } + + @Override + public final SmithyRpcV2ProtocolServiceClientConfiguration serviceClientConfiguration() { + return new SmithyRpcV2ProtocolServiceClientConfigurationBuilder(this.clientConfiguration.toBuilder()).build(); + } + + @Override + public void close() { + clientHandler.close(); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/emptyinputoutputrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/emptyinputoutputrequest-transformer.java new file mode 100644 index 000000000000..92b108916f55 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/emptyinputoutputrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.EmptyInputOutputRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link EmptyInputOutputRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class EmptyInputOutputRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/EmptyInputOutput").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(false).hasPayloadMembers(false).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public EmptyInputOutputRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(EmptyInputOutputRequest emptyInputOutputRequest) { + Validate.paramNotNull(emptyInputOutputRequest, "emptyInputOutputRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(emptyInputOutputRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/float16request-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/float16request-transformer.java new file mode 100644 index 000000000000..ab5bee8ecb3c --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/float16request-transformer.java @@ -0,0 +1,43 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.Float16Request; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link Float16Request} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class Float16RequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/Float16").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(false).hasPayloadMembers(false) + .putAdditionalMetadata(BaseAwsJsonProtocolFactory.GENERATES_BODY, false).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public Float16RequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(Float16Request float16Request) { + Validate.paramNotNull(float16Request, "float16Request"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(float16Request); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/fractionalsecondsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/fractionalsecondsrequest-transformer.java new file mode 100644 index 000000000000..6154dd5b71b9 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/fractionalsecondsrequest-transformer.java @@ -0,0 +1,43 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.FractionalSecondsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link FractionalSecondsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class FractionalSecondsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/FractionalSeconds").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(false).hasPayloadMembers(false) + .putAdditionalMetadata(BaseAwsJsonProtocolFactory.GENERATES_BODY, false).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public FractionalSecondsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(FractionalSecondsRequest fractionalSecondsRequest) { + Validate.paramNotNull(fractionalSecondsRequest, "fractionalSecondsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(fractionalSecondsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/greetingwitherrorsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/greetingwitherrorsrequest-transformer.java new file mode 100644 index 000000000000..0bc995433a9d --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/greetingwitherrorsrequest-transformer.java @@ -0,0 +1,43 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.GreetingWithErrorsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link GreetingWithErrorsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class GreetingWithErrorsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/GreetingWithErrors").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(false).hasPayloadMembers(false) + .putAdditionalMetadata(BaseAwsJsonProtocolFactory.GENERATES_BODY, false).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public GreetingWithErrorsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(GreetingWithErrorsRequest greetingWithErrorsRequest) { + Validate.paramNotNull(greetingWithErrorsRequest, "greetingWithErrorsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(greetingWithErrorsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/noinputoutputrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/noinputoutputrequest-transformer.java new file mode 100644 index 000000000000..e8cfbbb88f2b --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/noinputoutputrequest-transformer.java @@ -0,0 +1,43 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.NoInputOutputRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link NoInputOutputRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class NoInputOutputRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/NoInputOutput").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(false).hasPayloadMembers(false) + .putAdditionalMetadata(BaseAwsJsonProtocolFactory.GENERATES_BODY, false).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public NoInputOutputRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(NoInputOutputRequest noInputOutputRequest) { + Validate.paramNotNull(noInputOutputRequest, "noInputOutputRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(noInputOutputRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/operationwithdefaultsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/operationwithdefaultsrequest-transformer.java new file mode 100644 index 000000000000..6e15b413e1a5 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/operationwithdefaultsrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OperationWithDefaultsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link OperationWithDefaultsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class OperationWithDefaultsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/OperationWithDefaults").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public OperationWithDefaultsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(OperationWithDefaultsRequest operationWithDefaultsRequest) { + Validate.paramNotNull(operationWithDefaultsRequest, "operationWithDefaultsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(operationWithDefaultsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/optionalinputoutputrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/optionalinputoutputrequest-transformer.java new file mode 100644 index 000000000000..02a6b7943366 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/optionalinputoutputrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.OptionalInputOutputRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link OptionalInputOutputRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class OptionalInputOutputRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/OptionalInputOutput").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public OptionalInputOutputRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(OptionalInputOutputRequest optionalInputOutputRequest) { + Validate.paramNotNull(optionalInputOutputRequest, "optionalInputOutputRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(optionalInputOutputRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/recursiveshapesrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/recursiveshapesrequest-transformer.java new file mode 100644 index 000000000000..1c49c2013c8c --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/recursiveshapesrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RecursiveShapesRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link RecursiveShapesRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class RecursiveShapesRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/RecursiveShapes").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public RecursiveShapesRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(RecursiveShapesRequest recursiveShapesRequest) { + Validate.paramNotNull(recursiveShapesRequest, "recursiveShapesRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(recursiveShapesRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cbordensemapsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cbordensemapsrequest-transformer.java new file mode 100644 index 000000000000..370fa7edab09 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cbordensemapsrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborDenseMapsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link RpcV2CborDenseMapsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class RpcV2CborDenseMapsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/RpcV2CborDenseMaps").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public RpcV2CborDenseMapsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(RpcV2CborDenseMapsRequest rpcV2CborDenseMapsRequest) { + Validate.paramNotNull(rpcV2CborDenseMapsRequest, "rpcV2CborDenseMapsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(rpcV2CborDenseMapsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborlistsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborlistsrequest-transformer.java new file mode 100644 index 000000000000..348daeeba187 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborlistsrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborListsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link RpcV2CborListsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class RpcV2CborListsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/RpcV2CborLists").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public RpcV2CborListsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(RpcV2CborListsRequest rpcV2CborListsRequest) { + Validate.paramNotNull(rpcV2CborListsRequest, "rpcV2CborListsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(rpcV2CborListsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborsparsemapsrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborsparsemapsrequest-transformer.java new file mode 100644 index 000000000000..2de2cee3c1c0 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/rpcv2cborsparsemapsrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.RpcV2CborSparseMapsRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link RpcV2CborSparseMapsRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class RpcV2CborSparseMapsRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/RpcV2CborSparseMaps").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public RpcV2CborSparseMapsRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(RpcV2CborSparseMapsRequest rpcV2CborSparseMapsRequest) { + Validate.paramNotNull(rpcV2CborSparseMapsRequest, "rpcV2CborSparseMapsRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(rpcV2CborSparseMapsRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/simplescalarpropertiesrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/simplescalarpropertiesrequest-transformer.java new file mode 100644 index 000000000000..f96b8712c042 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/simplescalarpropertiesrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SimpleScalarPropertiesRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link SimpleScalarPropertiesRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class SimpleScalarPropertiesRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/SimpleScalarProperties").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public SimpleScalarPropertiesRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(SimpleScalarPropertiesRequest simpleScalarPropertiesRequest) { + Validate.paramNotNull(simpleScalarPropertiesRequest, "simpleScalarPropertiesRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(simpleScalarPropertiesRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/sparsenullsoperationrequest-transformer.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/sparsenullsoperationrequest-transformer.java new file mode 100644 index 000000000000..3a81e9a35c3c --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/transform/smithy_rpc_v2_cbor/sparsenullsoperationrequest-transformer.java @@ -0,0 +1,42 @@ +package software.amazon.awssdk.services.smithyrpcv2protocol.transform; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.runtime.transform.Marshaller; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.services.smithyrpcv2protocol.model.SparseNullsOperationRequest; +import software.amazon.awssdk.utils.Validate; + +/** + * {@link SparseNullsOperationRequest} Marshaller + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class SparseNullsOperationRequestMarshaller implements Marshaller { + private static final OperationInfo SDK_OPERATION_BINDING = OperationInfo.builder() + .requestUri("/service/RpcV2Protocol/operation/SparseNullsOperation").httpMethod(SdkHttpMethod.POST) + .hasExplicitPayloadMember(false).hasImplicitPayloadMembers(true).hasPayloadMembers(true).build(); + + private final BaseAwsJsonProtocolFactory protocolFactory; + + public SparseNullsOperationRequestMarshaller(BaseAwsJsonProtocolFactory protocolFactory) { + this.protocolFactory = protocolFactory; + } + + @Override + public SdkHttpFullRequest marshall(SparseNullsOperationRequest sparseNullsOperationRequest) { + Validate.paramNotNull(sparseNullsOperationRequest, "sparseNullsOperationRequest"); + try { + ProtocolMarshaller protocolMarshaller = protocolFactory + .createProtocolMarshaller(SDK_OPERATION_BINDING); + return protocolMarshaller.marshall(sparseNullsOperationRequest); + } catch (Exception e) { + throw SdkClientException.builder().message("Unable to marshall request to JSON: " + e.getMessage()).cause(e).build(); + } + } +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 2f63a78ba02b..693c70497dc9 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -42,6 +42,7 @@ import software.amazon.awssdk.protocols.core.OperationMetadataAttribute; import software.amazon.awssdk.protocols.core.ProtocolMarshaller; import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory; +import software.amazon.awssdk.protocols.json.internal.ProtocolFact; import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; import software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonErrorMessageParser; import software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonProtocolErrorUnmarshaller; @@ -55,7 +56,7 @@ public abstract class BaseAwsJsonProtocolFactory { /** * Used by operations that do not serialize the input, e.g., when the input is not defined in the model. RPCv2 uses it. */ - public static final OperationMetadataAttribute USE_NO_OP_GENERATOR = new OperationMetadataAttribute<>(Boolean.class); + public static final OperationMetadataAttribute GENERATES_BODY = new OperationMetadataAttribute<>(Boolean.class); /** * Attribute for a protocol to configure extra headers for the operation. @@ -149,12 +150,12 @@ private MetricCollectingHttpResponseHandler timeUnmarshalling(HttpRespons } private StructuredJsonGenerator createGenerator(OperationInfo operationInfo) { - Boolean useNoOp = operationInfo.addtionalMetadata(USE_NO_OP_GENERATOR); - if (useNoOp == null) { + Boolean generatesBody = operationInfo.addtionalMetadata(GENERATES_BODY); + if (generatesBody == null) { AwsJsonProtocol protocol = protocolMetadata.protocol(); - useNoOp = !operationInfo.hasPayloadMembers() && protocol != AwsJsonProtocol.AWS_JSON; + generatesBody = ProtocolFact.from(protocol).generatesBody(operationInfo); } - if (useNoOp) { + if (!generatesBody) { return StructuredJsonGenerator.NO_OP; } return createGenerator(); diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/ProtocolFact.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/ProtocolFact.java new file mode 100644 index 000000000000..f5fa9c3702e4 --- /dev/null +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/ProtocolFact.java @@ -0,0 +1,107 @@ +/* + * 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.protocols.json.internal; + +import java.util.Collections; +import java.util.Map; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.utils.MapUtils; + +/** + * Represents know static facts about each protocol. + */ +@SdkInternalApi +public interface ProtocolFact { + + /** + * Defaults used by all protocols that do not have overrides. + */ + ProtocolFact DEFAULT = new ProtocolFact() {}; + + /** + * Overrides for AWS JSON. + */ + ProtocolFact AWS_JSON = new ProtocolFact() { + + /** + * AWS JSON always generates body. + */ + @Override + public boolean generatesBody(OperationInfo info) { + return true; + } + }; + + /** + * Overrides for Smithy RPCv2. + */ + ProtocolFact SMITHY_RPC_V2_CBOR = new ProtocolFact() { + private final Map extraHeaders = Collections.unmodifiableMap(MapUtils.of("smithy-protocol", + "rpc-v2-cbor")); + /** + * Smithy RPCv2 only skips body generation for operation without input defined. These operations mark themselves using + * the {@link BaseAwsJsonProtocolFactory#GENERATES_BODY} metadata attribute. Otherwise, the protocol default is to + * generate a body for the operation. + */ + @Override + public boolean generatesBody(OperationInfo info) { + return true; + } + + /** + * Smithy RPCv2 always sends a header with key "smithy-protocol" and value "rpc-v2-cbor". + */ + @Override + public Map extraHeaders() { + return extraHeaders; + } + }; + + /** + * Returns true if the operation generates a body, false otherwise. By default, this depends on whether the operation input + * has members bound to the payload. + */ + default boolean generatesBody(OperationInfo info) { + return info.hasPayloadMembers(); + } + + /** + * Returns a configured set of headers to be added to each request of the protocol. + */ + default Map extraHeaders() { + return Collections.emptyMap(); + } + + /** + * Returns the object representing a collection of facts for each protocol. + */ + static ProtocolFact from(AwsJsonProtocol protocol) { + if (protocol == null) { + return DEFAULT; + } + switch (protocol) { + case SMITHY_RPC_V2_CBOR: + return SMITHY_RPC_V2_CBOR; + case AWS_JSON: + return AWS_JSON; + default: + return DEFAULT; + } + } +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java index 59122bc0b667..924803d47297 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java @@ -46,6 +46,7 @@ import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; +import software.amazon.awssdk.protocols.json.internal.ProtocolFact; /** * Implementation of {@link ProtocolMarshaller} for JSON based services. This includes JSON-RPC and REST-JSON. @@ -168,6 +169,10 @@ private SdkHttpFullRequest.Builder fillBasicRequestParams(OperationInfo operatio requestBuilder.putHeader("X-Amz-Target", operationIdentifier); } Map extraHeaders = operationInfo.addtionalMetadata(BaseAwsJsonProtocolFactory.HTTP_EXTRA_HEADERS); + if (extraHeaders == null) { + extraHeaders = + ProtocolFact.from(protocolMetadata.protocol()).extraHeaders(); + } if (extraHeaders != null) { extraHeaders.forEach(requestBuilder::putHeader); } From e141df1aef4866f3f19219d5143f78af0734f810 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Fri, 23 Aug 2024 10:03:13 -0700 Subject: [PATCH 09/14] Add RPCv2 benchmark tests (#5526) * Add RPCv2 benchmark tests * Give the constants name a meaningful name --- .../sdkrpcv2/customization.config | 4 + .../sdkrpcv2/endpoint-rule-set.json | 30 + .../sdkrpcv2/endpoint-tests.json | 5 + .../codegen-resources/sdkrpcv2/service-2.json | 684 ++++++++++++++++++ .../awssdk/benchmark/BenchmarkRunner.java | 3 +- .../benchmark/apicall/protocol/JsonCodec.java | 221 ++++++ .../protocol/JsonMarshallerBenchmark.java | 124 ++++ .../SmithyRpcV2ProtocolBenchmark.java | 75 ++ .../benchmark/utils/BenchmarkConstant.java | 40 + .../utils/BenchmarkConstantGetMetricData.java | 480 ++++++++++++ .../benchmark/utils/MockHttpClient.java | 22 +- 11 files changed, 1682 insertions(+), 6 deletions(-) create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/customization.config create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-rule-set.json create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-tests.json create mode 100644 test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/service-2.json create mode 100644 test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java create mode 100644 test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java create mode 100644 test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/SmithyRpcV2ProtocolBenchmark.java create mode 100644 test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstantGetMetricData.java diff --git a/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/customization.config b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/customization.config new file mode 100644 index 000000000000..4a57cda840dd --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/customization.config @@ -0,0 +1,4 @@ +{ + "enableGenerateCompiledEndpointRules": true, + "skipEndpointTestGeneration": true +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-rule-set.json b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-rule-set.json new file mode 100644 index 000000000000..88c1054e3482 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-rule-set.json @@ -0,0 +1,30 @@ +{ + "version": "1.3", + "parameters": { + "Region": { + "builtIn": "AWS::Region", + "required": true, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + } + }, + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "http://localhost/", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "jsonrpc" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-tests.json b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-tests.json new file mode 100644 index 000000000000..f94902ff9d99 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/endpoint-tests.json @@ -0,0 +1,5 @@ +{ + "testCases": [ + ], + "version": "1.0" +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/service-2.json new file mode 100644 index 000000000000..62357f2cf5f7 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/sdkrpcv2/service-2.json @@ -0,0 +1,684 @@ +{ + "version": "2.0", + "metadata": { + "apiVersion": "2016-03-11", + "endpointPrefix": "smithyrpcv2", + "jsonVersion": "1.1", + "protocol": "smithy-rpc-v2-cbor", + "protocols": [ + "smithy-rpc-v2-cbor" + ], + "serviceAbbreviation": "SmithyRpcV2ProtocolTests", + "serviceFullName": "Smithy RPCv2 Protocol Tests", + "serviceId": "ProtocolSmithyrpcv2", + "signatureVersion": "v4", + "targetPrefix": "ProtocolTestsSmithyRpcV2Service", + "uid": "smithyrpcv2-2016-03-11" + }, + "operations": { + "GetMetricData": { + "name": "GetMetricData", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "GetMetricDataRequest" + }, + "output": { + "shape": "GetMetricDataResponse" + } + }, + "AllTypes": { + "name": "AllTypes", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "AllTypesStructure" + }, + "output": { + "shape": "AllTypesStructure" + }, + "errors": [ + { + "shape": "EmptyModeledException" + }, + { + "shape": "ImplicitPayloadException" + } + ] + }, + "FurtherNestedContainers": { + "name": "FurtherNestedContainers", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "FurtherNestedContainersStructure" + }, + "output": { + "shape": "FurtherNestedContainersStructure" + } + }, + "IdempotentOperation": { + "name": "IdempotentOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "IdempotentOperationStructure" + }, + "output": { + "shape": "IdempotentOperationStructure" + } + }, + "NestedContainers": { + "name": "NestedContainers", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "NestedContainersStructure" + }, + "output": { + "shape": "NestedContainersStructure" + } + }, + "OperationWithNoInputOrOutput": { + "name": "OperationWithNoInputOrOutput", + "http": { + "method": "POST", + "requestUri": "/" + } + } + }, + "shapes": { + "GetMetricDataRequest": { + "type": "structure", + "members": { + "id": { + "shape": "String" + } + } + }, + "GetMetricDataResponse": { + "type": "structure", + "members": { + "id": { + "shape": "String" + }, + "label": { + "shape": "String" + }, + "statusCode": { + "shape": "StatusCode" + }, + "timestamps": { + "shape": "ListOfTimeStamp" + }, + "values": { + "shape": "ListOfDouble" + } + } + }, + "ListOfDouble": { + "type": "list", + "member": { + "shape": "Double" + } + }, + "StatusCode": { + "type": "string", + "enum": [ + "Complete", + "InProgess" + ] + }, + "AllTypesStructure": { + "type": "structure", + "members": { + "StringMember": { + "shape": "String" + }, + "IntegerMember": { + "shape": "Integer" + }, + "BooleanMember": { + "shape": "Boolean" + }, + "FloatMember": { + "shape": "Float" + }, + "DoubleMember": { + "shape": "Double" + }, + "BigDecimalMember": { + "shape": "NumericValue" + }, + "LongMember": { + "shape": "Long" + }, + "ShortMember": { + "shape": "Short" + }, + "ByteMember": { + "shape": "Byte" + }, + "SimpleList": { + "shape": "ListOfStrings" + }, + "ListOfMaps": { + "shape": "ListOfMapStringToString" + }, + "ListOfStructs": { + "shape": "ListOfSimpleStructs" + }, + "MapOfStringToIntegerList": { + "shape": "MapOfStringToIntegerList" + }, + "MapOfStringToString": { + "shape": "MapOfStringToString" + }, + "MapOfStringToStruct": { + "shape": "MapOfStringToSimpleStruct" + }, + "TimestampMember": { + "shape": "Timestamp" + }, + "StructWithNestedTimestampMember": { + "shape": "StructWithTimestamp" + }, + "TimestampFormatMember": { + "shape": "IsoTimestamp" + }, + "BlobArg": { + "shape": "BlobType" + }, + "StructWithNestedBlob": { + "shape": "StructWithNestedBlobType" + }, + "BlobMap": { + "shape": "BlobMapType" + }, + "ListOfBlobs": { + "shape": "ListOfBlobsType" + }, + "RecursiveStruct": { + "shape": "RecursiveStructType" + }, + "PolymorphicTypeWithSubTypes": { + "shape": "BaseType" + }, + "PolymorphicTypeWithoutSubTypes": { + "shape": "SubTypeOne" + }, + "EnumMember": { + "shape": "EnumType" + }, + "ListOfEnums": { + "shape": "ListOfEnums" + }, + "MapOfEnumToEnum": { + "shape": "MapOfEnumToEnum" + }, + "ListOfTimeStamp": { + "shape": "ListOfTimeStamp" + }, + "MapOfTimeStamp": { + "shape": "MapOfTimeStamp" + }, + "MyDocument": { + "shape": "MyDocument" + }, + "UnionMember": { + "shape": "AllTypesUnionStructure" + } + } + }, + "BaseType": { + "type": "structure", + "members": { + "BaseMember": { + "shape": "String" + } + } + }, + "BlobMapType": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "BlobType" + } + }, + "BlobType": { + "type": "blob" + }, + "Boolean": { + "type": "boolean" + }, + "Double": { + "type": "double" + }, + "EmptyModeledException": { + "type": "structure", + "members": {}, + "exception": true + }, + "EnumType": { + "type": "string", + "enum": [ + "EnumValue1", + "EnumValue2" + ] + }, + "Float": { + "type": "float" + }, + "Short": { + "type": "short" + }, + "Byte": { + "type": "byte" + }, + "FurtherNestedContainersStructure": { + "type": "structure", + "members": { + "ListOfNested": { + "shape": "ListOfNested" + } + } + }, + "IdempotentOperationStructure": { + "type": "structure", + "members": { + "IdempotencyToken": { + "shape": "String", + "idempotencyToken": true + } + } + }, + "ImplicitPayloadException": { + "type": "structure", + "members": { + "StringMember": { + "shape": "String" + }, + "IntegerMember": { + "shape": "Integer" + }, + "LongMember": { + "shape": "Long" + }, + "ShortMember": { + "shape": "Short" + }, + "DoubleMember": { + "shape": "Double" + }, + "FloatMember": { + "shape": "Float" + }, + "TimestampMember": { + "shape": "Timestamp" + }, + "BooleanMember": { + "shape": "Boolean" + }, + "BlobMember": { + "shape": "BlobType" + }, + "ListMember": { + "shape": "ListOfStrings" + }, + "MapMember": { + "shape": "MapOfStringToString" + }, + "SimpleStructMember": { + "shape": "SimpleStruct" + } + }, + "exception": true + }, + "Integer": { + "type": "integer" + }, + "NumericValue": { + "type": "string", + "pattern": "([0-9]*\\.)?[0-9]+" + }, + "IsoTimestamp": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "UnixTimestamp": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "ListOfAllTypesStructs": { + "type": "list", + "member": { + "shape": "AllTypesStructure" + } + }, + "ListOfBlobsType": { + "type": "list", + "member": { + "shape": "BlobType" + } + }, + "ListOfEnums": { + "type": "list", + "member": { + "shape": "EnumType" + } + }, + "ListOfIntegers": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "ListOfListOfListsOfStrings": { + "type": "list", + "member": { + "shape": "ListOfListsOfStrings" + } + }, + "ListOfListsOfAllTypesStructs": { + "type": "list", + "member": { + "shape": "ListOfAllTypesStructs" + } + }, + "ListOfListsOfStrings": { + "type": "list", + "member": { + "shape": "ListOfStrings" + } + }, + "ListOfListsOfStructs": { + "type": "list", + "member": { + "shape": "ListOfSimpleStructs" + } + }, + "ListOfMapStringToString": { + "type": "list", + "member": { + "shape": "MapOfStringToString" + } + }, + "ListOfNested": { + "type": "list", + "member": { + "shape": "NestedContainersStructure" + } + }, + "ListOfSimpleStructs": { + "type": "list", + "member": { + "shape": "SimpleStruct" + } + }, + "ListOfStrings": { + "type": "list", + "member": { + "shape": "String" + } + }, + "Long": { + "type": "long" + }, + "MapOfEnumToEnum": { + "type": "map", + "key": { + "shape": "EnumType" + }, + "value": { + "shape": "EnumType" + } + }, + "MapOfStringToIntegerList": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "ListOfIntegers" + } + }, + "MapOfStringToListOfListsOfStrings": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "ListOfListsOfStrings" + } + }, + "MapOfStringToSimpleStruct": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "SimpleStruct" + } + }, + "MapOfStringToString": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "NestedContainersStructure": { + "type": "structure", + "members": { + "ListOfListsOfStrings": { + "shape": "ListOfListsOfStrings" + }, + "ListOfListsOfStructs": { + "shape": "ListOfListsOfStructs" + }, + "ListOfListsOfAllTypesStructs": { + "shape": "ListOfListsOfAllTypesStructs" + }, + "ListOfListOfListsOfStrings": { + "shape": "ListOfListOfListsOfStrings" + }, + "MapOfStringToListOfListsOfStrings": { + "shape": "MapOfStringToListOfListsOfStrings" + }, + "StringMember": { + "shape": "String" + } + } + }, + "RecursiveListType": { + "type": "list", + "member": { + "shape": "RecursiveStructType" + } + }, + "RecursiveMapType": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "RecursiveStructType" + } + }, + "RecursiveStructType": { + "type": "structure", + "members": { + "NoRecurse": { + "shape": "String" + }, + "RecursiveStruct": { + "shape": "RecursiveStructType" + }, + "RecursiveList": { + "shape": "RecursiveListType" + }, + "RecursiveMap": { + "shape": "RecursiveMapType" + } + } + }, + "SimpleStruct": { + "type": "structure", + "members": { + "StringMember": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + }, + "StructWithNestedBlobType": { + "type": "structure", + "members": { + "NestedBlob": { + "shape": "BlobType" + } + } + }, + "StructWithTimestamp": { + "type": "structure", + "members": { + "NestedTimestamp": { + "shape": "Timestamp" + } + } + }, + "SubTypeOne": { + "type": "structure", + "members": { + "SubTypeOneMember": { + "shape": "String" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "ListOfTimeStamp": { + "type": "list", + "member": { + "shape": "UnixTimestamp" + } + }, + "MapOfTimeStamp": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "UnixTimestamp" + } + }, + "MyDocument": { + "type": "structure", + "document": true + }, + "AllTypesUnionStructure": { + "type": "structure", + "union": true, + "members": { + "StringMember": { + "shape": "String" + }, + "IntegerMember": { + "shape": "Integer" + }, + "BooleanMember": { + "shape": "Boolean" + }, + "FloatMember": { + "shape": "Float" + }, + "DoubleMember": { + "shape": "Double" + }, + "LongMember": { + "shape": "Long" + }, + "ShortMember": { + "shape": "Short" + }, + "EnumMember": { + "shape": "EnumType" + }, + "SimpleList": { + "shape": "ListOfStrings" + }, + "ListOfEnums": { + "shape": "ListOfEnums" + }, + "ListOfMaps": { + "shape": "ListOfMapStringToString" + }, + "ListOfStructs": { + "shape": "ListOfSimpleStructs" + }, + "MapOfStringToIntegerList": { + "shape": "MapOfStringToIntegerList" + }, + "MapOfStringToString": { + "shape": "MapOfStringToString" + }, + "MapOfStringToStruct": { + "shape": "MapOfStringToSimpleStruct" + }, + "MapOfEnumToEnum": { + "shape": "MapOfEnumToEnum" + }, + "TimestampMember": { + "shape": "Timestamp" + }, + "StructWithNestedTimestampMember": { + "shape": "StructWithTimestamp" + }, + "BlobArg": { + "shape": "BlobType" + }, + "StructWithNestedBlob": { + "shape": "StructWithNestedBlobType" + }, + "BlobMap": { + "shape": "BlobMapType" + }, + "ListOfBlobs": { + "shape": "ListOfBlobsType" + }, + "RecursiveStruct": { + "shape": "RecursiveStructType" + }, + "PolymorphicTypeWithSubTypes": { + "shape": "BaseType" + }, + "PolymorphicTypeWithoutSubTypes": { + "shape": "SubTypeOne" + }, + "SetPrefixedMember": { + "shape": "String" + }, + "UnionMember": { + "shape": "AllTypesUnionStructure" + } + } + } + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java index d63c1e2391e5..ca98ce400b6d 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java @@ -47,6 +47,7 @@ import software.amazon.awssdk.benchmark.apicall.protocol.Ec2ProtocolBenchmark; import software.amazon.awssdk.benchmark.apicall.protocol.JsonProtocolBenchmark; import software.amazon.awssdk.benchmark.apicall.protocol.QueryProtocolBenchmark; +import software.amazon.awssdk.benchmark.apicall.protocol.SmithyRpcV2ProtocolBenchmark; import software.amazon.awssdk.benchmark.apicall.protocol.XmlProtocolBenchmark; import software.amazon.awssdk.benchmark.coldstart.V2DefaultClientCreationBenchmark; import software.amazon.awssdk.benchmark.coldstart.V2OptimizedClientCreationBenchmark; @@ -67,6 +68,7 @@ public class BenchmarkRunner { private static final List PROTOCOL_BENCHMARKS = Arrays.asList( Ec2ProtocolBenchmark.class.getSimpleName(), JsonProtocolBenchmark.class.getSimpleName(), + SmithyRpcV2ProtocolBenchmark.class.getSimpleName(), QueryProtocolBenchmark.class.getSimpleName(), XmlProtocolBenchmark.class.getSimpleName()); private static final List ASYNC_BENCHMARKS = Arrays.asList( @@ -114,7 +116,6 @@ public static void main(String... args) throws Exception { benchmarksToRun.addAll(ASYNC_BENCHMARKS); benchmarksToRun.addAll(PROTOCOL_BENCHMARKS); benchmarksToRun.addAll(COLD_START_BENCHMARKS); - log.info(() -> "Skipping tests, to reduce benchmark times: \n" + MAPPER_BENCHMARKS + "\n" + METRIC_BENCHMARKS); BenchmarkRunner runner = new BenchmarkRunner(benchmarksToRun, parseOptions(args)); diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java new file mode 100644 index 000000000000..a2afb3a2bdcb --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java @@ -0,0 +1,221 @@ +/* + * 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.benchmark.apicall.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Supplier; +import software.amazon.awssdk.core.SdkPojo; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.protocols.core.OperationInfo; +import software.amazon.awssdk.protocols.core.ProtocolMarshaller; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; +import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata; +import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; +import software.amazon.awssdk.protocols.json.StructuredJsonFactory; +import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; +import software.amazon.awssdk.utils.IoUtils; + +/** + * A codec to marshall/unmarshall shapes using a JSON protocol. + */ +public final class JsonCodec { + + private static final SdkClientConfiguration EMPTY_CLIENT_CONFIGURATION = SdkClientConfiguration.builder() + .build(); + private static final OperationInfo EMPTY_OPERATION_INFO = OperationInfo.builder() + .httpMethod(SdkHttpMethod.POST) + .hasImplicitPayloadMembers(true) + .build(); + private static final Map TIMESTAMP_FORMATS = timestampFormats(); + + + /** + * Returns the bytes as a SdkPojo instance. + */ + public SdkPojo unmarshall(AwsJsonProtocol protocol, SdkPojo pojo, byte[] bytes) { + try { + ProtocolBehavior behavior = ProtocolBehavior.from(protocol); + JsonProtocolUnmarshaller unmarshaller = + JsonProtocolUnmarshaller + .builder() + .parser(JsonNodeParser.builder() + .jsonFactory(behavior.structuredJsonFactory().getJsonFactory()) + .build()) + .defaultTimestampFormats(behavior.timestampFormats()) + .build(); + SdkHttpFullResponse response = SdkHttpFullResponse + .builder() + .statusCode(200) + .putHeader("Content-Type", behavior.contentType()) + .content(AbortableInputStream.create(new ByteArrayInputStream(bytes))) + .build(); + return unmarshaller.unmarshall(pojo, response); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the SdkPojo instance bytes marshalling. + */ + public byte[] marshall(AwsJsonProtocol protocol, SdkPojo pojo) { + try { + ProtocolBehavior behavior = ProtocolBehavior.from(protocol); + ProtocolMarshaller marshaller = + JsonProtocolMarshallerBuilder.create() + .endpoint(new URI("http://localhost/")) + .jsonGenerator(behavior.structuredJsonFactory().createWriter(behavior.contentType())) + .contentType(behavior.contentType()) + .operationInfo(behavior.operationInfo()) + .sendExplicitNullForPayload(false) + .protocolMetadata(behavior.protocolMetadata()) + .build(); + SdkHttpFullRequest req = marshaller.marshall(pojo); + if (req.contentStreamProvider().isPresent()) { + return IoUtils.toByteArray(req.contentStreamProvider().get().newStream()); + } + } catch (IOException | URISyntaxException e) { + throw new RuntimeException(e); + } + return null; + } + + static Supplier getStructuredJsonFactory(BaseAwsJsonProtocolFactory factory) { + return () -> { + try { + Method method = BaseAwsJsonProtocolFactory.class.getDeclaredMethod("getSdkFactory"); + method.setAccessible(true); + return (StructuredJsonFactory) method.invoke(factory); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + static Map timestampFormats() { + Map formats = new EnumMap<>(MarshallLocation.class); + formats.put(MarshallLocation.HEADER, TimestampFormatTrait.Format.RFC_822); + formats.put(MarshallLocation.PAYLOAD, TimestampFormatTrait.Format.UNIX_TIMESTAMP); + return Collections.unmodifiableMap(formats); + } + + enum ProtocolBehavior { + SMITHY_RPC_V2_CBOR(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) { + AwsJsonProtocolMetadata metadata = AwsJsonProtocolMetadata.builder() + .protocol(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) + .build(); + BaseAwsJsonProtocolFactory factory = SmithyRpcV2CborProtocolFactory.builder() + .protocol(AwsJsonProtocol.SMITHY_RPC_V2_CBOR) + .clientConfiguration(EMPTY_CLIENT_CONFIGURATION) + .build(); + Supplier structuredJsonFactory = getStructuredJsonFactory(factory); + + @Override + public AwsJsonProtocolMetadata protocolMetadata() { + return metadata; + } + + @Override + public StructuredJsonFactory structuredJsonFactory() { + return structuredJsonFactory.get(); + } + + @Override + public String contentType() { + return "application/cbor"; + } + + }, + AWS_JSON(AwsJsonProtocol.AWS_JSON) { + AwsJsonProtocolMetadata metadata = AwsJsonProtocolMetadata.builder() + .protocol(AwsJsonProtocol.AWS_JSON) + .contentType("application/json") + .build(); + + BaseAwsJsonProtocolFactory factory = AwsJsonProtocolFactory.builder() + .protocol(AwsJsonProtocol.AWS_JSON) + .clientConfiguration(EMPTY_CLIENT_CONFIGURATION) + .build(); + + Supplier structuredJsonFactory = getStructuredJsonFactory(factory); + + @Override + public AwsJsonProtocolMetadata protocolMetadata() { + return metadata; + } + + @Override + public StructuredJsonFactory structuredJsonFactory() { + return structuredJsonFactory.get(); + } + }, + ; + + private final AwsJsonProtocol protocol; + + ProtocolBehavior(AwsJsonProtocol protocol) { + this.protocol = protocol; + } + + public AwsJsonProtocolMetadata protocolMetadata() { + throw new UnsupportedOperationException(); + } + + public StructuredJsonFactory structuredJsonFactory() { + throw new UnsupportedOperationException(); + } + + public Map timestampFormats() { + return TIMESTAMP_FORMATS; + } + + public OperationInfo operationInfo() { + return EMPTY_OPERATION_INFO; + } + + public String contentType() { + return "application/json"; + } + + public static ProtocolBehavior from(AwsJsonProtocol protocol) { + switch (protocol) { + case SMITHY_RPC_V2_CBOR: + return SMITHY_RPC_V2_CBOR; + case AWS_JSON: + return AWS_JSON; + default: + throw new IllegalArgumentException("only SMITHY_RPC_V2_CBOR and AWS_JSON are supported"); + } + } + } +} \ No newline at end of file diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java new file mode 100644 index 000000000000..23827a3d42a1 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java @@ -0,0 +1,124 @@ +/* + * 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.benchmark.apicall.protocol; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.profile.StackProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import software.amazon.awssdk.benchmark.utils.BenchmarkConstantGetMetricData; +import software.amazon.awssdk.protocols.json.AwsJsonProtocol; +import software.amazon.awssdk.services.protocolsmithyrpcv2.model.GetMetricDataResponse; + +/** + * Benchmarking for running with different protocols. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) +@Fork(1) // To reduce difference between each run +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +public class JsonMarshallerBenchmark { + + @State(Scope.Thread) + public static class MarshallingState { + @Param( {"small", "medium", "big"}) + public String size; + + @Param( {"smithy-rpc-v2", "aws-json"}) + public String protocol; + + GetMetricDataResponse data; + AwsJsonProtocol jsonProtocol; + private JsonCodec codec; + private byte[] rawBytes; + + @Setup(Level.Trial) + public void setup() { + jsonProtocol = AwsJsonProtocol.SMITHY_RPC_V2_CBOR; + if (protocol != null) { + switch (protocol) { + case "smithy-rpc-v2": + jsonProtocol = AwsJsonProtocol.SMITHY_RPC_V2_CBOR; + break; + case "aws-json": + jsonProtocol = AwsJsonProtocol.AWS_JSON; + break; + default: + throw new IllegalArgumentException("protocol: " + protocol); + } + } + + byte[] payload = null; + String payloadSize = "small"; + if (size != null) { + payloadSize = size; + } + switch (payloadSize) { + case "small": + payload = BenchmarkConstantGetMetricData.smallPayload().getBytes(StandardCharsets.UTF_8); + break; + case "medium": + payload = BenchmarkConstantGetMetricData.medPayload().getBytes(StandardCharsets.UTF_8); + break; + case "big": + payload = BenchmarkConstantGetMetricData.bigPayload().getBytes(StandardCharsets.UTF_8); + break; + default: + throw new IllegalArgumentException("size: " + size); + } + codec = new JsonCodec(); + data = (GetMetricDataResponse) codec.unmarshall(AwsJsonProtocol.AWS_JSON, + GetMetricDataResponse.builder(), + payload); + rawBytes = codec.marshall(jsonProtocol, data); + } + } + + @Benchmark + public void marshall(MarshallingState state, Blackhole blackhole) { + blackhole.consume(state.codec.marshall(state.jsonProtocol, state.data)); + } + + @Benchmark + public void unmarshall(MarshallingState state, Blackhole blackhole) { + blackhole.consume(state.codec.unmarshall(state.jsonProtocol, GetMetricDataResponse.builder(), state.rawBytes)); + } + + public static void main(String... args) throws Exception { + Options opt = new OptionsBuilder() + .include(JsonMarshallerBenchmark.class.getSimpleName()) + .addProfiler(StackProfiler.class) + .build(); + new Runner(opt).run(); + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/SmithyRpcV2ProtocolBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/SmithyRpcV2ProtocolBenchmark.java new file mode 100644 index 000000000000..a014c060072a --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/SmithyRpcV2ProtocolBenchmark.java @@ -0,0 +1,75 @@ +/* + * 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.benchmark.apicall.protocol; + +import static software.amazon.awssdk.benchmark.utils.BenchmarkConstant.ENCODED_SMITHY_RPCV2_BODY; +import static software.amazon.awssdk.benchmark.utils.BenchmarkConstant.ERROR_ENCODED_SMITHY_RPCV2_BODY; +import static software.amazon.awssdk.benchmark.utils.BenchmarkConstant.RPCV2_ALL_TYPES_REQUEST; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.profile.StackProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import software.amazon.awssdk.benchmark.utils.MockHttpClient; +import software.amazon.awssdk.services.protocolsmithyrpcv2.ProtocolSmithyrpcv2Client; + +/** + * Benchmarking for running with different protocols. + */ +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 15, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Fork(2) // To reduce difference between each run +@BenchmarkMode(Mode.Throughput) +public class SmithyRpcV2ProtocolBenchmark implements SdkProtocolBenchmark { + + private ProtocolSmithyrpcv2Client client; + + @Setup(Level.Trial) + public void setup() { + client = ProtocolSmithyrpcv2Client.builder() + .httpClient(MockHttpClient.fromEncoded(ENCODED_SMITHY_RPCV2_BODY, + ERROR_ENCODED_SMITHY_RPCV2_BODY)) + .build(); + } + + @Override + @Benchmark + public void successfulResponse(Blackhole blackhole) { + blackhole.consume(client.allTypes(RPCV2_ALL_TYPES_REQUEST)); + } + + public static void main(String... args) throws Exception { + Options opt = new OptionsBuilder() + .include(SmithyRpcV2ProtocolBenchmark.class.getSimpleName()) + .addProfiler(StackProfiler.class) + .build(); + new Runner(opt).run(); + } +} + diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstant.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstant.java index c241ac25b4b3..6d711bf46a89 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstant.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstant.java @@ -39,6 +39,24 @@ public final class BenchmarkConstant { public static final String ERROR_JSON_BODY = "{}"; + public static final String ENCODED_SMITHY_RPCV2_BODY = "" + + "bf6c537472696e674d656d62657263666f6f6d49" + + "6e74656765724d656d626572187b6d426f6f6c65" + + "616e4d656d626572f56b466c6f61744d656d6265" + + "72187b6c446f75626c654d656d626572fb405ef9" + + "999999999a6a4c6f6e674d656d626572187b6a53" + + "696d706c654c6973748169736f2073696d706c65" + + "6d4c6973744f665374727563747381bf6c537472" + + "696e674d656d6265726e6c6973744f6653747275" + + "63747331ff6f54696d657374616d704d656d6265" + + "72c1fb41d6f66221b8c49c781f53747275637457" + + "6974684e657374656454696d657374616d704d65" + + "6d626572bf6f4e657374656454696d657374616d" + + "70c1fb41d6f66221ba1cacff67426c6f62417267" + + "4b68656c6c6f20776f726c64ff"; + + public static final String ERROR_ENCODED_SMITHY_RPCV2_BODY = "bfff"; + public static final String JSON_BODY = "{\"StringMember\":\"foo\",\"IntegerMember\":123,\"BooleanMember\":true," + "\"FloatMember\":123.0,\"DoubleMember\":123.9,\"LongMember\":123," + "\"SimpleList\":[\"so simple\"]," @@ -155,6 +173,28 @@ public final class BenchmarkConstant { .blobArg(SdkBytes.fromUtf8String("hello " + "world")) .build(); + + public static final software.amazon.awssdk.services.protocolsmithyrpcv2.model.AllTypesRequest RPCV2_ALL_TYPES_REQUEST = + software.amazon.awssdk.services.protocolsmithyrpcv2.model.AllTypesRequest.builder() + .stringMember("foo") + .integerMember(123) + .booleanMember(true) + .floatMember(123.0f) + .doubleMember(123.9) + .longMember(123L) + .simpleList("so simple") + .listOfStructs(b -> b.stringMember( + "listOfStructs1").stringMember( + "listOfStructs1")) + .timestampMember( + TIMESTAMP_MEMBER) + .structWithNestedTimestampMember( + b -> b.nestedTimestamp( + TIMESTAMP_MEMBER)) + .blobArg(SdkBytes.fromUtf8String("hello " + + "world")) + .build(); + public static final AllTypesRequest EC2_ALL_TYPES_REQUEST = AllTypesRequest.builder() .stringMember("foo") diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstantGetMetricData.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstantGetMetricData.java new file mode 100644 index 000000000000..8ad97d6e52e6 --- /dev/null +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/BenchmarkConstantGetMetricData.java @@ -0,0 +1,480 @@ +/* + * 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.benchmark.utils; + +public final class BenchmarkConstantGetMetricData { + + private BenchmarkConstantGetMetricData() { + } + + public static String smallPayload() { + return "" + + "{" + + "\"id\": \"e3e8a1e2-9263-4f84-8f55-a02b5294f898\"," + + "\"statusCode\": \"complete\"," + + "\"timestamps\": [" + + "1724202608.473," + + "1724190262.001," + + "1724198190.366," + + "1724189802.664," + + "1724190757.916," + + "1724199387.642," + + "1724188193.764," + + "1724200821.781," + + "1724190627.248," + + "1724191634.580," + + "1724187698.198," + + "1724198980.827," + + "1724186311.588," + + "1724202584.189," + + "1724186735.437," + + "1724202645.908," + + "1724199467.177" + + "]," + + "\"values\": [" + + "0.7809395768021804," + + "0.023915630484810046," + + "0.5724624732139355," + + "0.5321357263091369," + + "0.6679717620524951," + + "0.4341153255382939," + + "0.3520929093415339," + + "0.2692001178989337," + + "0.07293650838473875," + + "0.9409684065533697," + + "0.2260762204804554," + + "0.5436300837472587," + + "0.020887739179190956," + + "0.3061308431374449," + + "0.30779168240420884," + + "0.9066297415697038," + + "0.25970596393553114" + + "]" + + "}"; + } + + public static String medPayload() { + return "" + + "{" + + "\"id\": \"5318013b-ae7b-44e3-ac6b-881ea346836e\"," + + "\"statusCode\": \"complete\"," + + "\"timestamps\": [" + + "1724190695.735," + + "1724193400.714," + + "1724192635.006," + + "1724201947.463," + + "1724192123.809," + + "1724195208.582," + + "1724192644.248," + + "1724199870.320," + + "1724195217.535," + + "1724193888.158," + + "1724202247.417," + + "1724188408.687," + + "1724192598.105," + + "1724183748.815," + + "1724189209.731," + + "1724189039.787," + + "1724184797.956," + + "1724200850.176," + + "1724200791.965," + + "1724199372.101," + + "1724189782.349," + + "1724194303.242," + + "1724185579.871," + + "1724183774.597," + + "1724200643.537," + + "1724187601.148," + + "1724184200.386," + + "1724202041.349," + + "1724191540.081," + + "1724201423.196," + + "1724184690.126," + + "1724198444.520," + + "1724184987.210," + + "1724201749.504," + + "1724191868.277," + + "1724189880.783," + + "1724191298.135" + + "]," + + "\"values\": [" + + "0.3947754216751095," + + "0.4139133068316505," + + "0.22138110817640333," + + "0.29428575554570824," + + "0.7827081366587345," + + "0.1867653288336255," + + "0.688227478220542," + + "0.024926444423126304," + + "0.7599985690318128," + + "0.022013908833974694," + + "0.4117809956997631," + + "0.962658010210074," + + "0.883537260896327," + + "0.6255331515381098," + + "0.24534881328756908," + + "0.22416727709832718," + + "0.4908764912464938," + + "0.614255350194121," + + "0.4540660016513067," + + "0.23992841358221328," + + "0.8889677405645506," + + "0.5950384192215744," + + "0.6826445288716654," + + "0.822884164190338," + + "0.30183221657410564," + + "0.03855584397939038," + + "0.6929617241503245," + + "0.3186388125143601," + + "0.03875709184257581," + + "0.7829375257972994," + + "0.12446076106144544," + + "0.6192771191531226," + + "0.8422701376381713," + + "0.31214124007349997," + + "0.7436049151543886," + + "0.8428546423890224," + + "0.3667666930834682" + + "]" + + "}"; + } + + public static String bigPayload() { + return "" + + "{" + + "\"id\": \"08d8dbdd-3c8c-4dc3-a5dc-6610f2d6856d\"," + + "\"statusCode\": \"Complete\"," + + "\"timestamps\": [" + + "1724195195.772," + + "1724188529.894," + + "1724198609.915," + + "1724189429.251," + + "1724197547.806," + + "1724192060.009," + + "1724189650.932," + + "1724186507.404," + + "1724199715.866," + + "1724194476.941," + + "1724183461.041," + + "1724184964.550," + + "1724190035.773," + + "1724183937.831," + + "1724187398.508," + + "1724191589.130," + + "1724192264.824," + + "1724192626.390," + + "1724201964.126," + + "1724201080.059," + + "1724186206.311," + + "1724186640.304," + + "1724201833.373," + + "1724186567.136," + + "1724184830.833," + + "1724194937.093," + + "1724196145.732," + + "1724197818.728," + + "1724189825.804," + + "1724202221.255," + + "1724186359.238," + + "1724187095.252," + + "1724197820.016," + + "1724193070.684," + + "1724185996.190," + + "1724183328.028," + + "1724197797.464," + + "1724183733.943," + + "1724184454.018," + + "1724201064.316," + + "1724196667.297," + + "1724184705.822," + + "1724187343.166," + + "1724198361.623," + + "1724200709.650," + + "1724202128.490," + + "1724195683.729," + + "1724200064.523," + + "1724191920.788," + + "1724193121.337," + + "1724198361.856," + + "1724199878.370," + + "1724201307.644," + + "1724196140.577," + + "1724192524.506," + + "1724190833.371," + + "1724183906.291," + + "1724198886.347," + + "1724187974.001," + + "1724196034.766," + + "1724186522.608," + + "1724200205.552," + + "1724193884.581," + + "1724200487.508," + + "1724191063.764," + + "1724199703.885," + + "1724198972.081," + + "1724192391.610," + + "1724184089.888," + + "1724187614.127," + + "1724193142.050," + + "1724190702.485," + + "1724184131.983," + + "1724191192.770," + + "1724195364.648," + + "1724200187.412," + + "1724202687.707," + + "1724190507.897," + + "1724192692.804," + + "1724193574.364," + + "1724200288.205," + + "1724185661.647," + + "1724191149.763," + + "1724185151.399," + + "1724186846.946," + + "1724202349.049," + + "1724189011.901," + + "1724195607.680," + + "1724194872.867," + + "1724188155.082," + + "1724193525.041," + + "1724197404.364," + + "1724188901.253," + + "1724201982.456," + + "1724193005.460," + + "1724197728.488," + + "1724186008.204," + + "1724194850.883," + + "1724183345.687," + + "1724191542.563," + + "1724183672.287," + + "1724185785.859," + + "1724185209.033," + + "1724201015.491," + + "1724186947.301," + + "1724183284.122," + + "1724198064.669," + + "1724196868.090," + + "1724200687.238," + + "1724191616.368," + + "1724188222.468," + + "1724187425.788," + + "1724198416.185," + + "1724201787.357," + + "1724187912.330," + + "1724202412.679," + + "1724187381.601," + + "1724202605.715," + + "1724186809.221," + + "1724201779.309," + + "1724185833.036," + + "1724197657.401," + + "1724190366.332," + + "1724197445.642," + + "1724200001.185," + + "1724202009.133," + + "1724188756.517," + + "1724201960.218," + + "1724191893.481," + + "1724187101.914," + + "1724187327.428," + + "1724200806.391," + + "1724200931.470," + + "1724200124.372," + + "1724202831.401," + + "1724187134.790," + + "1724200572.752," + + "1724198484.822," + + "1724198940.706," + + "1724202567.119," + + "1724196928.842," + + "1724193706.365," + + "1724184064.338," + + "1724202484.375," + + "1724199797.380," + + "1724196338.046," + + "1724184081.544," + + "1724188817.778," + + "1724184119.751," + + "1724190189.370," + + "1724189503.328," + + "1724197679.031," + + "1724196691.765," + + "1724201768.401," + + "1724196233.625," + + "1724196325.691," + + "1724185039.576" + + "]," + + "\"values\": [" + + "0.5142502349407903," + + "0.27991368995626265," + + "0.796919983881862," + + "0.4265447884272576," + + "0.05973644172948411," + + "0.24920900714243444," + + "0.163454826737518," + + "0.11412612136088185," + + "0.46573034571715155," + + "0.9035369285690061," + + "0.4180378022002985," + + "0.5232941612432238," + + "0.5963626083159036," + + "0.24488729375685314," + + "0.42651532616932364," + + "0.3776576526361488," + + "0.6482532332420919," + + "0.6486085703139249," + + "0.2644166808690386," + + "0.7307256058483557," + + "0.8166096182061666," + + "0.19268307211871727," + + "0.7727104730202957," + + "0.35466363320683136," + + "0.09683989322087794," + + "0.9333726667957042," + + "0.24451320368662155," + + "0.4890694919600982," + + "0.5396377875536456," + + "0.9542281796627965," + + "0.1724476333285072," + + "0.8557020548274251," + + "0.42938514798143346," + + "0.18615978469672345," + + "0.9064555436165841," + + "0.06437095542883431," + + "0.23781334977429125," + + "0.8222443935887971," + + "0.7015268217074727," + + "0.7966802068045832," + + "0.2230933402550932," + + "0.07280798451671777," + + "0.5376208370917134," + + "0.18278750628050366," + + "0.43561490545671877," + + "0.6611606572667783," + + "0.3643331539342698," + + "0.028684287238130768," + + "0.6621455986580506," + + "0.6946185638789135," + + "0.6580753223935177," + + "0.4662977491906568," + + "0.9884008656250945," + + "0.8933079314056721," + + "0.5596190380364333," + + "0.2431290582671446," + + "0.8895740542333967," + + "0.1096489802851579," + + "0.5345506382647307," + + "0.7952987839724576," + + "0.47061236732352185," + + "0.9582142136833215," + + "0.3224114914124927," + + "0.6427963647489302," + + "0.3384601712699046," + + "0.22642319652067677," + + "0.8840824990154296," + + "0.7585909727404917," + + "0.2966668931954406," + + "0.18134357331401074," + + "0.7345248617856133," + + "0.5882357799906722," + + "0.6830214721432004," + + "0.7501731042365603," + + "0.6451214237420626," + + "0.041207491893985204," + + "0.65237700188474," + + "0.6251880530254181," + + "0.036635131241643415," + + "0.959660932743443," + + "0.37334479307892177," + + "0.19332387211601842," + + "0.11670639152646678," + + "0.7660682088505728," + + "0.3834873022490275," + + "0.8111895193650964," + + "0.8689711564370434," + + "0.38682850580668804," + + "0.1841136484403506," + + "0.7006160564921254," + + "0.23525963438755482," + + "0.5577079037689573," + + "0.9381205558474971," + + "0.25313533131030286," + + "0.3869643246045321," + + "0.5722738474798688," + + "0.711097166013533," + + "0.9904509924511158," + + "0.9659404717695363," + + "0.6979086086804972," + + "0.893430627335319," + + "0.6132438820939561," + + "0.05354587625144147," + + "0.39094107107419995," + + "0.5363858855462161," + + "0.5510537886964366," + + "0.3987040322754084," + + "0.17231836060984418," + + "0.8083885756191823," + + "0.7396359443127422," + + "0.13581227171784727," + + "0.009173369080357485," + + "0.07449511127444985," + + "0.4430412034893876," + + "0.7701201354723839," + + "0.476260489817258," + + "0.6525778251439672," + + "0.2146980498091987," + + "0.878880092638996," + + "0.811249104360527," + + "0.703397394667801," + + "0.5227986538338281," + + "0.47894877723942675," + + "0.6645938274324242," + + "0.05674941410773837," + + "0.6562166873698134," + + "0.970387453497928," + + "0.7429272901916414," + + "0.9823873486581615," + + "0.08245787075243405," + + "0.1757558413478637," + + "0.32169771935452307," + + "0.34204009895173004," + + "0.09879505335810002," + + "0.11797251160371258," + + "0.7910154954877386," + + "0.8565927111703568," + + "0.22405267660547012," + + "0.155066313457755," + + "0.3142293316678516," + + "0.518748652433129," + + "0.97028821460209," + + "0.316217168698393," + + "0.03535065391078007," + + "0.769541041125665," + + "0.41375402074159096," + + "0.4909858741737354," + + "0.3293316289999356," + + "0.31862070653206487," + + "0.08806449162082008," + + "0.077153063553007," + + "0.27319142472457736," + + "0.2991314694451198," + + "0.9268462031573227," + + "0.8056430485368917," + + "0.11325370780391131," + + "0.9565011306712682" + + "]" + + "}"; + } +} diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/MockHttpClient.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/MockHttpClient.java index 1f3f9d8d5853..a200bc672172 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/MockHttpClient.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/MockHttpClient.java @@ -17,26 +17,38 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.ExecutableHttpRequest; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.utils.BinaryUtils; /** * Mock implementation of {@link SdkHttpClient} to return mock response. */ public final class MockHttpClient implements SdkHttpClient { - private String successResponseContent; - private String errorResponseContent; + private byte[] successResponseContent; + private byte[] errorResponseContent; - public MockHttpClient(String successResponseContent, String errorResponseContent) { + public MockHttpClient(byte[] successResponseContent, byte[] errorResponseContent) { this.successResponseContent = successResponseContent; this.errorResponseContent = errorResponseContent; } + public MockHttpClient(String successResponseContent, String errorResponseContent) { + this(successResponseContent.getBytes(StandardCharsets.UTF_8), + errorResponseContent.getBytes(StandardCharsets.UTF_8)); + } + + public static MockHttpClient fromEncoded(String encodedSuccessResponseContent, String encodedErrorResponseContent) { + return new MockHttpClient(BinaryUtils.fromHex(encodedSuccessResponseContent), + BinaryUtils.fromHex(encodedErrorResponseContent)); + } + @Override public ExecutableHttpRequest prepareRequest(HttpExecuteRequest request) { if (request.httpRequest().firstMatchingHeader("stub-error").isPresent()) { @@ -71,7 +83,7 @@ public void abort() { private HttpExecuteResponse successResponse() { AbortableInputStream inputStream = - AbortableInputStream.create(new ByteArrayInputStream(successResponseContent.getBytes())); + AbortableInputStream.create(new ByteArrayInputStream(successResponseContent)); return HttpExecuteResponse.builder() .response(SdkHttpResponse.builder() @@ -84,7 +96,7 @@ private HttpExecuteResponse successResponse() { private HttpExecuteResponse errorResponse() { AbortableInputStream inputStream = - AbortableInputStream.create(new ByteArrayInputStream(errorResponseContent.getBytes())); + AbortableInputStream.create(new ByteArrayInputStream(errorResponseContent)); return HttpExecuteResponse.builder() .response(SdkHttpResponse.builder() From 36ed1a2842f6cc64d7122e4daf1bc3e2fc2ef76b Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Thu, 29 Aug 2024 09:44:23 -0700 Subject: [PATCH 10/14] Avoid parsing numbers when using RPCv2 protocol (#5539) * Avoid parsing numbers when using RPCv2 protocol --- .../protocols/jsoncore/JsonNodeParser.java | 24 +-- .../jsoncore/JsonValueNodeFactory.java | 58 ++++++++ .../json/BaseAwsJsonProtocolFactory.java | 9 ++ .../unmarshall/JsonProtocolUnmarshaller.java | 139 ++++++++++++++++-- .../protocols/core/NumberToInstant.java | 82 +++++++++++ core/protocols/smithy-rpcv2-protocol/pom.xml | 5 + .../rpcv2/SmithyRpcV2CborProtocolFactory.java | 7 + .../SdkRpcV2CborValueNodeFactory.java | 102 +++++++++++++ .../benchmark/apicall/protocol/JsonCodec.java | 13 +- .../protocol/JsonMarshallerBenchmark.java | 4 +- 10 files changed, 419 insertions(+), 24 deletions(-) create mode 100644 core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonValueNodeFactory.java create mode 100644 core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java diff --git a/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonNodeParser.java b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonNodeParser.java index f87100eab1f5..d85e1efbfadf 100644 --- a/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonNodeParser.java +++ b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonNodeParser.java @@ -25,12 +25,8 @@ import java.util.Map; import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.protocols.jsoncore.internal.ArrayJsonNode; -import software.amazon.awssdk.protocols.jsoncore.internal.BooleanJsonNode; import software.amazon.awssdk.protocols.jsoncore.internal.EmbeddedObjectJsonNode; -import software.amazon.awssdk.protocols.jsoncore.internal.NullJsonNode; -import software.amazon.awssdk.protocols.jsoncore.internal.NumberJsonNode; import software.amazon.awssdk.protocols.jsoncore.internal.ObjectJsonNode; -import software.amazon.awssdk.protocols.jsoncore.internal.StringJsonNode; import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory; import software.amazon.awssdk.thirdparty.jackson.core.JsonParseException; import software.amazon.awssdk.thirdparty.jackson.core.JsonParser; @@ -55,10 +51,12 @@ public final class JsonNodeParser { private final boolean removeErrorLocations; private final JsonFactory jsonFactory; + private final JsonValueNodeFactory jsonValueNodeFactory; private JsonNodeParser(Builder builder) { this.removeErrorLocations = builder.removeErrorLocations; this.jsonFactory = builder.jsonFactory; + this.jsonValueNodeFactory = builder.jsonValueNodeFactory; } /** @@ -144,16 +142,12 @@ private JsonNode parseToken(JsonParser parser, JsonToken token) throws IOExcepti } switch (token) { case VALUE_STRING: - return new StringJsonNode(parser.getText()); case VALUE_FALSE: - return new BooleanJsonNode(false); case VALUE_TRUE: - return new BooleanJsonNode(true); case VALUE_NULL: - return NullJsonNode.instance(); case VALUE_NUMBER_FLOAT: case VALUE_NUMBER_INT: - return new NumberJsonNode(parser.getText()); + return jsonValueNodeFactory.node(parser, token); case START_OBJECT: return parseObject(parser); case START_ARRAY: @@ -191,6 +185,7 @@ private JsonNode parseArray(JsonParser parser) throws IOException { */ public static final class Builder { private JsonFactory jsonFactory = DEFAULT_JSON_FACTORY; + private JsonValueNodeFactory jsonValueNodeFactory = JsonValueNodeFactory.DEFAULT; private boolean removeErrorLocations = false; private Builder() { @@ -221,6 +216,17 @@ public Builder jsonFactory(JsonFactory jsonFactory) { return this; } + /** + * Factory to create JsonNode out of JSON tokens. This allows JSON variants, such as CBOR, to produce actual values + * instead of having to parse them out of strings. + * + *

By default, this is {@link JsonValueNodeFactory#DEFAULT}. + */ + public Builder jsonValueNodeFactory(JsonValueNodeFactory jsonValueNodeFactory) { + this.jsonValueNodeFactory = jsonValueNodeFactory; + return this; + } + /** * Build a {@link JsonNodeParser} based on the current configuration of this builder. */ diff --git a/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonValueNodeFactory.java b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonValueNodeFactory.java new file mode 100644 index 000000000000..028c0bdb1742 --- /dev/null +++ b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonValueNodeFactory.java @@ -0,0 +1,58 @@ +/* + * 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.protocols.jsoncore; + +import java.io.IOException; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.protocols.jsoncore.internal.BooleanJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.EmbeddedObjectJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.NullJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.NumberJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.StringJsonNode; +import software.amazon.awssdk.thirdparty.jackson.core.JsonParser; +import software.amazon.awssdk.thirdparty.jackson.core.JsonToken; + +/** + * Parses JSON tokens into JsonNode's values. Used only for atomic values. + */ +@SdkProtectedApi +public interface JsonValueNodeFactory { + + /** + * Default implementation. Takes the tokens and returns JsonNode values based on its string representation. + */ + JsonValueNodeFactory DEFAULT = (parser, token) -> { + switch (token) { + case VALUE_STRING: + return new StringJsonNode(parser.getText()); + case VALUE_FALSE: + return new BooleanJsonNode(false); + case VALUE_TRUE: + return new BooleanJsonNode(true); + case VALUE_NULL: + return NullJsonNode.instance(); + case VALUE_NUMBER_FLOAT: + case VALUE_NUMBER_INT: + return new NumberJsonNode(parser.getText()); + case VALUE_EMBEDDED_OBJECT: + return new EmbeddedObjectJsonNode(parser.getEmbeddedObject()); + default: + throw new IllegalArgumentException("Unexpected JSON token - " + token); + } + }; + + JsonNode node(JsonParser parser, JsonToken token) throws IOException; +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 693c70497dc9..975475c5207b 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -50,6 +50,7 @@ import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonResponseHandler; import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; @SdkProtectedApi public abstract class BaseAwsJsonProtocolFactory { @@ -88,6 +89,7 @@ protected BaseAwsJsonProtocolFactory(Builder builder) { .builder() .parser(JsonNodeParser.builder() .jsonFactory(getSdkFactory().getJsonFactory()) + .jsonValueNodeFactory(getJsonValueNodeFactory()) .build()) .defaultTimestampFormats(getDefaultTimestampFormats()) .build(); @@ -179,6 +181,13 @@ protected JsonContentTypeResolver getContentTypeResolver() { return AWS_JSON; } + /** + * @return Default JsonNode value factory. + */ + protected JsonValueNodeFactory getJsonValueNodeFactory() { + return JsonValueNodeFactory.DEFAULT; + } + /** * @return Instance of {@link StructuredJsonFactory} to use in creating handlers. */ diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java index e55a75797c91..b9f25716c241 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java @@ -18,12 +18,14 @@ import static software.amazon.awssdk.protocols.core.StringToValueConverter.TO_SDK_BYTES; import java.io.IOException; +import java.math.BigDecimal; import java.time.Instant; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.ThreadSafe; @@ -39,6 +41,7 @@ import software.amazon.awssdk.core.traits.TimestampFormatTrait; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.protocols.core.NumberToInstant; import software.amazon.awssdk.protocols.core.StringToInstant; import software.amazon.awssdk.protocols.core.StringToValueConverter; import software.amazon.awssdk.protocols.json.internal.MarshallerUtil; @@ -57,6 +60,8 @@ public final class JsonProtocolUnmarshaller { public final StringToValueConverter.StringToValue instantStringToValue; + private final NumberToInstant numberToInstant; + private final JsonUnmarshallerRegistry registry; private final JsonNodeParser parser; @@ -66,11 +71,16 @@ private JsonProtocolUnmarshaller(Builder builder) { this.instantStringToValue = StringToInstant.create(builder.defaultTimestampFormats.isEmpty() ? new EnumMap<>(MarshallLocation.class) : new EnumMap<>(builder.defaultTimestampFormats)); - this.registry = createUnmarshallerRegistry(instantStringToValue); + this.numberToInstant = NumberToInstant.create(builder.defaultTimestampFormats.isEmpty() ? + new EnumMap<>(MarshallLocation.class) : + new EnumMap<>(builder.defaultTimestampFormats)); + this.registry = createUnmarshallerRegistry(instantStringToValue, numberToInstant); } private static JsonUnmarshallerRegistry createUnmarshallerRegistry( - StringToValueConverter.StringToValue instantStringToValue) { + StringToValueConverter.StringToValue instantStringToValue, + NumberToInstant numberToInstant + ) { return JsonUnmarshallerRegistry .builder() @@ -86,17 +96,24 @@ private static JsonUnmarshallerRegistry createUnmarshallerRegistry( .headerUnmarshaller(MarshallingType.LIST, HeaderUnmarshaller.LIST) .payloadUnmarshaller(MarshallingType.STRING, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_STRING)) - .payloadUnmarshaller(MarshallingType.INTEGER, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_INTEGER)) - .payloadUnmarshaller(MarshallingType.LONG, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_LONG)) - .payloadUnmarshaller(MarshallingType.BYTE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_BYTE)) - .payloadUnmarshaller(MarshallingType.SHORT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_SHORT)) - .payloadUnmarshaller(MarshallingType.FLOAT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_FLOAT)) - .payloadUnmarshaller(MarshallingType.DOUBLE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_DOUBLE)) - .payloadUnmarshaller(MarshallingType.BIG_DECIMAL, new SimpleTypeJsonUnmarshaller<>( - StringToValueConverter.TO_BIG_DECIMAL)) - .payloadUnmarshaller(MarshallingType.BOOLEAN, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_BOOLEAN)) + .payloadUnmarshaller(MarshallingType.INTEGER, forEmbeddable(Number.class, Number::intValue, + StringToValueConverter.TO_INTEGER)) + .payloadUnmarshaller(MarshallingType.LONG, forEmbeddable(Number.class, Number::longValue, + StringToValueConverter.TO_LONG)) + .payloadUnmarshaller(MarshallingType.BYTE, forEmbeddable(Number.class, Number::byteValue, + StringToValueConverter.TO_BYTE)) + .payloadUnmarshaller(MarshallingType.SHORT, forEmbeddable(Number.class, Number::shortValue, + StringToValueConverter.TO_SHORT)) + .payloadUnmarshaller(MarshallingType.FLOAT, forEmbeddable(Number.class, Number::floatValue, + StringToValueConverter.TO_FLOAT)) + .payloadUnmarshaller(MarshallingType.DOUBLE, forEmbeddable(Number.class, Number::doubleValue, + StringToValueConverter.TO_DOUBLE)) + .payloadUnmarshaller(MarshallingType.BIG_DECIMAL, forEmbeddable(BigDecimal.class, + StringToValueConverter.TO_BIG_DECIMAL)) + .payloadUnmarshaller(MarshallingType.BOOLEAN, forEmbeddable(Boolean.class, StringToValueConverter.TO_BOOLEAN)) .payloadUnmarshaller(MarshallingType.SDK_BYTES, JsonProtocolUnmarshaller::unmarshallSdkBytes) - .payloadUnmarshaller(MarshallingType.INSTANT, new SimpleTypeJsonUnmarshaller<>(instantStringToValue)) + .payloadUnmarshaller(MarshallingType.INSTANT, new SimpleTypeInstantJsonUnmarshaller<>(instantStringToValue, + numberToInstant)) .payloadUnmarshaller(MarshallingType.SDK_POJO, JsonProtocolUnmarshaller::unmarshallStructured) .payloadUnmarshaller(MarshallingType.LIST, JsonProtocolUnmarshaller::unmarshallList) .payloadUnmarshaller(MarshallingType.MAP, JsonProtocolUnmarshaller::unmarshallMap) @@ -186,6 +203,104 @@ public T unmarshall(JsonUnmarshallerContext context, } } + private static class EmbeddableTypeTransformingJsonUnmarshaller implements JsonUnmarshaller { + + private final StringToValueConverter.StringToValue stringToValue; + private final Class embeddedType; + private final Function typeConverter; + + private EmbeddableTypeTransformingJsonUnmarshaller( + Class embeddedType, + Function typeConverter, + StringToValueConverter.StringToValue stringToValue + ) { + this.stringToValue = stringToValue; + this.typeConverter = typeConverter; + this.embeddedType = embeddedType; + } + + @Override + public T unmarshall(JsonUnmarshallerContext context, + JsonNode jsonContent, + SdkField field) { + if (jsonContent == null || jsonContent.isNull()) { + return null; + } + String text = null; + if (jsonContent.isEmbeddedObject()) { + Object embedded = jsonContent.asEmbeddedObject(); + if (embedded == null) { + return null; + } + if (embeddedType.isAssignableFrom(embedded.getClass())) { + return typeConverter.apply((V) embedded); + } + // Fallback in case that the embedded object is not what + // we were looking for. + text = embedded.toString(); + } + if (text == null) { + text = jsonContent.text(); + } + return stringToValue.convert(text, field); + } + } + + private static class SimpleTypeInstantJsonUnmarshaller implements JsonUnmarshaller { + + private final StringToValueConverter.StringToValue stringToValue; + private final NumberToInstant numberToInstant; + + private SimpleTypeInstantJsonUnmarshaller( + StringToValueConverter.StringToValue stringToValue, + NumberToInstant numberToInstant + ) { + this.stringToValue = stringToValue; + this.numberToInstant = numberToInstant; + } + + @Override + public T unmarshall(JsonUnmarshallerContext context, + JsonNode jsonContent, + SdkField field) { + if (jsonContent == null || jsonContent.isNull()) { + return null; + } + String text = null; + if (jsonContent.isEmbeddedObject()) { + Object embedded = jsonContent.asEmbeddedObject(); + if (embedded == null) { + return null; + } + if (Number.class.isAssignableFrom(embedded.getClass())) { + return (T) numberToInstant.convert((Number) embedded, (SdkField) field); + } + // Fallback in case that the embedded object is not what + // we were looking for. + text = embedded.toString(); + } + if (text == null) { + text = jsonContent.text(); + } + return stringToValue.convert(text, field); + } + } + + private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( + Class embeddedType, + Function transformer, + StringToValueConverter.StringToValue stringToValue + ) { + return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, transformer, stringToValue); + } + + private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( + Class embeddedType, + StringToValueConverter.StringToValue stringToValue + ) { + return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, Function.identity(), stringToValue); + } + public TypeT unmarshall(SdkPojo sdkPojo, SdkHttpFullResponse response) throws IOException { JsonNode jsonNode = hasJsonPayload(sdkPojo, response) ? parser.parse(response.content().get()) : null; diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java new file mode 100644 index 000000000000..4c91db234bb5 --- /dev/null +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java @@ -0,0 +1,82 @@ +/* + * 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.protocols.core; + +import java.time.Instant; +import java.util.Map; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.SdkField; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; + +/** + * Converts a number value to an {@link Instant} type. Respects the {@link TimestampFormatTrait} if present. + */ +@SdkProtectedApi +public final class NumberToInstant { + + /** + * Default formats for the given location. + */ + private final Map defaultFormats; + private final StringToInstant stringToInstant; + + private NumberToInstant(Map defaultFormats) { + this.stringToInstant = StringToInstant.create(defaultFormats); + this.defaultFormats = defaultFormats; + } + + public Instant convert(Number value, SdkField field) { + if (value == null) { + return null; + } + if (field.location() != MarshallLocation.PAYLOAD) { + return stringToInstant.convert(value.toString(), field); + } + TimestampFormatTrait.Format format = resolveTimestampFormat(field); + switch (format) { + case UNIX_TIMESTAMP: + return Instant.ofEpochMilli((long) (value.doubleValue() * 1_000d)); + case UNIX_TIMESTAMP_MILLIS: + return Instant.ofEpochMilli(value.longValue()); + default: + return stringToInstant.convert(value.toString(), field); + } + } + + private TimestampFormatTrait.Format resolveTimestampFormat(SdkField field) { + TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class); + if (trait == null) { + TimestampFormatTrait.Format format = defaultFormats.get(field.location()); + if (format == null) { + throw SdkClientException.create( + String.format("Timestamps are not supported for this location (%s)", field.location())); + } + return format; + } else { + return trait.format(); + } + } + + /** + * @param defaultFormats Default formats for each {@link MarshallLocation} as defined by the protocol. + * @return New {@link StringToValueConverter.StringToValue} for {@link Instant} types. + */ + public static NumberToInstant create(Map defaultFormats) { + return new NumberToInstant(defaultFormats); + } +} diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml index 3daf142e8f33..7c5507653219 100644 --- a/core/protocols/smithy-rpcv2-protocol/pom.xml +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -56,6 +56,11 @@ third-party-jackson-core ${awsjavasdk.version} + + software.amazon.awssdk + json-utils + ${awsjavasdk.version} + org.junit.jupiter junit-jupiter diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java index e3b76bdba065..0cb8d6fcd239 100644 --- a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java @@ -24,6 +24,8 @@ import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.JsonContentTypeResolver; import software.amazon.awssdk.protocols.json.StructuredJsonFactory; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkRpcV2CborValueNodeFactory; import software.amazon.awssdk.protocols.rpcv2.internal.SdkStructuredRpcV2CborFactory; /** @@ -65,6 +67,11 @@ protected Map getDefaultTimestamp return LazyHolder.DEFAULT_TIMESTAMP_FORMATS; } + @Override + public JsonValueNodeFactory getJsonValueNodeFactory() { + return SdkRpcV2CborValueNodeFactory.INSTANCE; + } + public static Builder builder() { return new Builder(); } diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java new file mode 100644 index 000000000000..f85136221492 --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java @@ -0,0 +1,102 @@ +/* + * 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.protocols.rpcv2.internal; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.protocols.jsoncore.internal.EmbeddedObjectJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.NullJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.NumberJsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.StringJsonNode; +import software.amazon.awssdk.thirdparty.jackson.core.JsonParser; +import software.amazon.awssdk.thirdparty.jackson.core.JsonToken; +import software.amazon.awssdk.thirdparty.jackson.dataformat.cbor.CBORParser; + +/** + * Factory to create JsonNodes that can embed values from the CBOR parser. + */ +@SdkInternalApi +public final class SdkRpcV2CborValueNodeFactory implements JsonValueNodeFactory { + public static final JsonValueNodeFactory INSTANCE = new SdkRpcV2CborValueNodeFactory(); + + private SdkRpcV2CborValueNodeFactory() { + } + + @Override + public JsonNode node(JsonParser parser, JsonToken token) throws IOException { + if (!(parser instanceof CBORParser)) { + return DEFAULT.node(parser, token); + } + + switch (token) { + case VALUE_STRING: + return new StringJsonNode(parser.getText()); + case VALUE_FALSE: + return new EmbeddedObjectJsonNode(false); + case VALUE_TRUE: + return new EmbeddedObjectJsonNode(true); + case VALUE_NULL: + return NullJsonNode.instance(); + case VALUE_NUMBER_FLOAT: + case VALUE_NUMBER_INT: + return nodeForNumber(parser, token); + case VALUE_EMBEDDED_OBJECT: + return new EmbeddedObjectJsonNode(parser.getEmbeddedObject()); + default: + throw new IllegalArgumentException("Unexpected JSON token - " + token); + } + } + + private JsonNode nodeForNumber(JsonParser parser, JsonToken token) throws IOException { + JsonParser.NumberType numberType = parser.getNumberType(); + switch (numberType) { + case INT: + case LONG: + case FLOAT: + case DOUBLE: + try { + Number javaNumber = parser.getNumberValue(); + return new EmbeddedObjectJsonNode(javaNumber); + } catch (Exception e) { + // ignored + } + break; + case BIG_DECIMAL: + try { + BigDecimal bigDecimal = parser.getDecimalValue(); + return new EmbeddedObjectJsonNode(bigDecimal); + } catch (Exception e) { + // ignored + } + break; + case BIG_INTEGER: + try { + BigInteger bigInteger = parser.getBigIntegerValue(); + return new EmbeddedObjectJsonNode(bigInteger); + } catch (Exception e) { + // ignored + } + break; + default: + } + return new NumberJsonNode(parser.getText()); + } +} + diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java index a2afb3a2bdcb..86a3ae0d6dd2 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java @@ -42,7 +42,9 @@ import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkRpcV2CborValueNodeFactory; import software.amazon.awssdk.utils.IoUtils; /** @@ -70,6 +72,7 @@ public SdkPojo unmarshall(AwsJsonProtocol protocol, SdkPojo pojo, byte[] bytes) .builder() .parser(JsonNodeParser.builder() .jsonFactory(behavior.structuredJsonFactory().getJsonFactory()) + .jsonValueNodeFactory(behavior.jsonValueNodeFactory()) .build()) .defaultTimestampFormats(behavior.timestampFormats()) .build(); @@ -150,6 +153,11 @@ public StructuredJsonFactory structuredJsonFactory() { return structuredJsonFactory.get(); } + @Override + public JsonValueNodeFactory jsonValueNodeFactory() { + return SdkRpcV2CborValueNodeFactory.INSTANCE; + } + @Override public String contentType() { return "application/cbor"; @@ -161,7 +169,6 @@ public String contentType() { .protocol(AwsJsonProtocol.AWS_JSON) .contentType("application/json") .build(); - BaseAwsJsonProtocolFactory factory = AwsJsonProtocolFactory.builder() .protocol(AwsJsonProtocol.AWS_JSON) .clientConfiguration(EMPTY_CLIENT_CONFIGURATION) @@ -195,6 +202,10 @@ public StructuredJsonFactory structuredJsonFactory() { throw new UnsupportedOperationException(); } + public JsonValueNodeFactory jsonValueNodeFactory() { + return JsonValueNodeFactory.DEFAULT; + } + public Map timestampFormats() { return TIMESTAMP_FORMATS; } diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java index 23827a3d42a1..596fe8a7bd4e 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonMarshallerBenchmark.java @@ -51,10 +51,10 @@ public class JsonMarshallerBenchmark { @State(Scope.Thread) public static class MarshallingState { - @Param( {"small", "medium", "big"}) + @Param({"small", "medium", "big"}) public String size; - @Param( {"smithy-rpc-v2", "aws-json"}) + @Param({"smithy-rpc-v2", "aws-json"}) public String protocol; GetMetricDataResponse data; From ec773cdab14fb4c2dba564109a8b8aed0fa2856b Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Tue, 3 Sep 2024 11:01:02 -0700 Subject: [PATCH 11/14] Refactor to avoid impacting JSON with RPCv2 logic (#5544) * Refactor to avoid impacting JSON with RPCv2 logic * Avoid making the unmarshallers depend on timestamp formats * Avoid streams while unmarshalling * Fix build failures * Fix build failures 2 --- core/protocols/aws-cbor-protocol/pom.xml | 14 + .../cbor/AwsCborProtocolFactory.java | 50 ++- .../cbor/AwsCborProtocolFactoryTest.java | 19 +- .../json/AwsJsonProtocolFactory.java | 2 + .../json/BaseAwsJsonProtocolFactory.java | 41 +-- .../DefaultJsonUnmarshallerRegistry.java | 90 ++++++ ...DefaultProtocolUnmarshallDependencies.java | 94 ++++++ .../unmarshall/JsonProtocolUnmarshaller.java | 291 ++++++++---------- .../unmarshall/JsonUnmarshallerRegistry.java | 52 +--- .../ProtocolUnmarshallDependencies.java | 52 ++++ .../UnmarshallerRegistryFactory.java | 31 ++ .../json/FaultStatusCodeMappingTest.java | 1 + .../core/AbstractMarshallingRegistry.java | 17 + core/protocols/smithy-rpcv2-protocol/pom.xml | 10 + .../rpcv2/SmithyRpcV2CborProtocolFactory.java | 38 ++- .../internal/SdkRpcV2CborUnmarshaller.java | 202 ++++++++++++ .../SdkRpcV2CborValueNodeFactory.java | 27 +- .../enhanced/dynamodb/JsonTestUtils.java | 41 +++ .../document/BasicQueryTest.java | 67 ++-- .../document/BasicScanTest.java | 39 +-- .../benchmark/apicall/protocol/JsonCodec.java | 28 +- 21 files changed, 864 insertions(+), 342 deletions(-) create mode 100644 core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultJsonUnmarshallerRegistry.java create mode 100644 core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultProtocolUnmarshallDependencies.java create mode 100644 core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/ProtocolUnmarshallDependencies.java create mode 100644 core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/UnmarshallerRegistryFactory.java create mode 100644 core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborUnmarshaller.java create mode 100644 services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/JsonTestUtils.java diff --git a/core/protocols/aws-cbor-protocol/pom.xml b/core/protocols/aws-cbor-protocol/pom.xml index cb272b11482f..03377618ade2 100644 --- a/core/protocols/aws-cbor-protocol/pom.xml +++ b/core/protocols/aws-cbor-protocol/pom.xml @@ -46,6 +46,16 @@ annotations ${awsjavasdk.version} + + software.amazon.awssdk + json-utils + ${awsjavasdk.version} + + + software.amazon.awssdk + utils + ${awsjavasdk.version} + software.amazon.awssdk third-party-jackson-dataformat-cbor @@ -81,6 +91,10 @@ mockito-core test + + software.amazon.awssdk + test-utils + diff --git a/core/protocols/aws-cbor-protocol/src/main/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactory.java b/core/protocols/aws-cbor-protocol/src/main/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactory.java index 429dd76e0e73..decef4691b07 100644 --- a/core/protocols/aws-cbor-protocol/src/main/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactory.java +++ b/core/protocols/aws-cbor-protocol/src/main/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactory.java @@ -28,6 +28,11 @@ import software.amazon.awssdk.protocols.json.DefaultJsonContentTypeResolver; import software.amazon.awssdk.protocols.json.JsonContentTypeResolver; import software.amazon.awssdk.protocols.json.StructuredJsonFactory; +import software.amazon.awssdk.protocols.json.internal.unmarshall.DefaultProtocolUnmarshallDependencies; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.protocols.json.internal.unmarshall.ProtocolUnmarshallDependencies; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.utils.Lazy; /** * Protocol factory for AWS/CBOR protocols. Supports both JSON RPC and REST JSON versions of CBOR. Defaults to @@ -37,13 +42,23 @@ @SdkProtectedApi public final class AwsCborProtocolFactory extends BaseAwsJsonProtocolFactory { + private static final Lazy PROTOCOL_UNMARSHALL_DEPENDENCIES_LAZY = + new Lazy<>(AwsCborProtocolFactory::newProtocolUnmarshallDependencies); + /** * Content type resolver implementation for AWS_CBOR enabled services. */ private static final JsonContentTypeResolver AWS_CBOR = new DefaultJsonContentTypeResolver("application/x-amz-cbor-"); + /** + * Indicates whether CBOR is enabled for this factory. This is populated and build time and not longer checked against the + * system setting + */ + private final boolean isSdkSystemSettingCborEnabled; + private AwsCborProtocolFactory(Builder builder) { super(builder); + this.isSdkSystemSettingCborEnabled = builder.isSdkSystemSettingCborEnabled; } /** @@ -74,7 +89,6 @@ protected StructuredJsonFactory getSdkFactory() { */ @Override protected Map getDefaultTimestampFormats() { - // If Cbor is disabled, getting the default timestamp format from parent class if (!isCborEnabled()) { return super.getDefaultTimestampFormats(); @@ -87,6 +101,10 @@ protected Map getDefaultTimestamp } private boolean isCborEnabled() { + return isSdkSystemSettingCborEnabled; + } + + private static boolean isSdkSystemSettingCborEnabled() { return SdkSystemSetting.CBOR_ENABLED.getBooleanValueOrThrow(); } @@ -94,17 +112,45 @@ public static Builder builder() { return new Builder(); } + public static ProtocolUnmarshallDependencies defaultProtocolUnmarshallDependencies() { + return PROTOCOL_UNMARSHALL_DEPENDENCIES_LAZY.getValue(); + } + + public static DefaultProtocolUnmarshallDependencies newProtocolUnmarshallDependencies() { + return DefaultProtocolUnmarshallDependencies + .builder() + .jsonUnmarshallerRegistry(JsonProtocolUnmarshaller.timestampFormatRegistryFactory(defaultFormats())) + .nodeValueFactory(JsonValueNodeFactory.DEFAULT) + .timestampFormats(defaultFormats()) + .jsonFactory(AwsStructuredCborFactory.SDK_CBOR_FACTORY.getJsonFactory()) + .build(); + } + + private static Map defaultFormats() { + Map formats = new EnumMap<>(MarshallLocation.class); + formats.put(MarshallLocation.HEADER, TimestampFormatTrait.Format.RFC_822); + formats.put(MarshallLocation.PAYLOAD, TimestampFormatTrait.Format.UNIX_TIMESTAMP_MILLIS); + return Collections.unmodifiableMap(formats); + + } + /** * Builder for {@link AwsJsonProtocolFactory}. */ public static final class Builder extends BaseAwsJsonProtocolFactory.Builder { + private boolean isSdkSystemSettingCborEnabled = isSdkSystemSettingCborEnabled(); + private Builder() { } public AwsCborProtocolFactory build() { + if (this.isSdkSystemSettingCborEnabled) { + protocolUnmarshallDependencies(AwsCborProtocolFactory::defaultProtocolUnmarshallDependencies); + } else { + protocolUnmarshallDependencies(JsonProtocolUnmarshaller::defaultProtocolUnmarshallDependencies); + } return new AwsCborProtocolFactory(this); } - } } diff --git a/core/protocols/aws-cbor-protocol/src/test/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactoryTest.java b/core/protocols/aws-cbor-protocol/src/test/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactoryTest.java index 961510922379..4d21b0453bd3 100644 --- a/core/protocols/aws-cbor-protocol/src/test/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactoryTest.java +++ b/core/protocols/aws-cbor-protocol/src/test/java/software/amazon/awssdk/protocols/cbor/AwsCborProtocolFactoryTest.java @@ -22,22 +22,16 @@ import static software.amazon.awssdk.core.traits.TimestampFormatTrait.Format.UNIX_TIMESTAMP_MILLIS; import java.util.Map; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.testutils.EnvironmentVariableHelper; public class AwsCborProtocolFactoryTest { - private static AwsCborProtocolFactory factory; - - @BeforeAll - public static void setup() { - factory = AwsCborProtocolFactory.builder().build(); - } - @Test public void defaultTimestampFormats_cborEnabled() { + AwsCborProtocolFactory factory = AwsCborProtocolFactory.builder().build(); Map defaultTimestampFormats = factory.getDefaultTimestampFormats(); assertThat(defaultTimestampFormats.get(MarshallLocation.HEADER)).isEqualTo(RFC_822); assertThat(defaultTimestampFormats.get(MarshallLocation.PAYLOAD)).isEqualTo(UNIX_TIMESTAMP_MILLIS); @@ -45,13 +39,12 @@ public void defaultTimestampFormats_cborEnabled() { @Test public void defaultTimestampFormats_cborDisabled() { - System.setProperty(CBOR_ENABLED.property(), "false"); - try { + EnvironmentVariableHelper.run(helper -> { + helper.set(CBOR_ENABLED, "false"); + AwsCborProtocolFactory factory = AwsCborProtocolFactory.builder().build(); Map defaultTimestampFormats = factory.getDefaultTimestampFormats(); assertThat(defaultTimestampFormats.get(MarshallLocation.HEADER)).isEqualTo(RFC_822); assertThat(defaultTimestampFormats.get(MarshallLocation.PAYLOAD)).isEqualTo(UNIX_TIMESTAMP); - } finally { - System.clearProperty(CBOR_ENABLED.property()); - } + }); } } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocolFactory.java index fe6217c5f431..b15fd9dc93d7 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/AwsJsonProtocolFactory.java @@ -17,6 +17,7 @@ import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; /** * Factory to generate the various JSON protocol handlers and generators to be used for @@ -40,6 +41,7 @@ public static Builder builder() { public static final class Builder extends BaseAwsJsonProtocolFactory.Builder { private Builder() { + protocolUnmarshallDependencies(JsonProtocolUnmarshaller::defaultProtocolUnmarshallDependencies); } public AwsJsonProtocolFactory build() { diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java index 975475c5207b..8d6fe845a109 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/BaseAwsJsonProtocolFactory.java @@ -49,8 +49,7 @@ import software.amazon.awssdk.protocols.json.internal.unmarshall.AwsJsonResponseHandler; import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonResponseHandler; -import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; -import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.protocols.json.internal.unmarshall.ProtocolUnmarshallDependencies; @SdkProtectedApi public abstract class BaseAwsJsonProtocolFactory { @@ -85,14 +84,11 @@ protected BaseAwsJsonProtocolFactory(Builder builder) { this.customErrorCodeFieldName = builder.customErrorCodeFieldName; this.hasAwsQueryCompatible = builder.hasAwsQueryCompatible; this.clientConfiguration = builder.clientConfiguration; - this.protocolUnmarshaller = JsonProtocolUnmarshaller - .builder() - .parser(JsonNodeParser.builder() - .jsonFactory(getSdkFactory().getJsonFactory()) - .jsonValueNodeFactory(getJsonValueNodeFactory()) - .build()) - .defaultTimestampFormats(getDefaultTimestampFormats()) - .build(); + this.protocolUnmarshaller = JsonProtocolUnmarshaller.builder() + .protocolUnmarshallDependencies( + builder.protocolUnmarshallDependencies.get()) + .build(); + } /** @@ -181,13 +177,6 @@ protected JsonContentTypeResolver getContentTypeResolver() { return AWS_JSON; } - /** - * @return Default JsonNode value factory. - */ - protected JsonValueNodeFactory getJsonValueNodeFactory() { - return JsonValueNodeFactory.DEFAULT; - } - /** * @return Instance of {@link StructuredJsonFactory} to use in creating handlers. */ @@ -221,7 +210,8 @@ public final ProtocolMarshaller createProtocolMarshaller(Ope * Builder for {@link AwsJsonProtocolFactory}. */ public abstract static class Builder { - + protected Supplier protocolUnmarshallDependencies = + JsonProtocolUnmarshaller::defaultProtocolUnmarshallDependencies; private final AwsJsonProtocolMetadata.Builder protocolMetadata = AwsJsonProtocolMetadata.builder(); private final List modeledExceptions = new ArrayList<>(); private Supplier defaultServiceExceptionSupplier; @@ -322,10 +312,23 @@ public final SubclassT hasAwsQueryCompatible(boolean hasAwsQueryCompatible) { return getSubclass(); } + /** + * Provides the unmarshalling dependencies instance. + * + * @param protocolUnmarshallDependencies the set of dependencies used to create an unmarshaller + * @return This builder for method chaining. + */ + protected final SubclassT protocolUnmarshallDependencies( + Supplier protocolUnmarshallDependencies + ) { + this.protocolUnmarshallDependencies = protocolUnmarshallDependencies; + return getSubclass(); + } + @SuppressWarnings("unchecked") private SubclassT getSubclass() { return (SubclassT) this; } - } + } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultJsonUnmarshallerRegistry.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultJsonUnmarshallerRegistry.java new file mode 100644 index 000000000000..4364401d6bd6 --- /dev/null +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultJsonUnmarshallerRegistry.java @@ -0,0 +1,90 @@ +/* + * 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.protocols.json.internal.unmarshall; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.protocols.core.AbstractMarshallingRegistry; + +/** + * Registry of {@link JsonUnmarshaller} implementations by location and type. + */ +@SdkInternalApi +public final class DefaultJsonUnmarshallerRegistry extends AbstractMarshallingRegistry implements JsonUnmarshallerRegistry { + + private DefaultJsonUnmarshallerRegistry(Builder builder) { + super(builder); + } + + @Override + @SuppressWarnings("unchecked") + public JsonUnmarshaller getUnmarshaller(MarshallLocation marshallLocation, MarshallingType marshallingType) { + return (JsonUnmarshaller) get(marshallLocation, marshallingType); + } + + /** + * Returns a builder to modify this registry. + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * @return Builder instance to construct a {@link DefaultJsonUnmarshallerRegistry}. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for a {@link DefaultJsonUnmarshallerRegistry}. + */ + public static final class Builder extends AbstractMarshallingRegistry.Builder { + + private Builder(DefaultJsonUnmarshallerRegistry unmarshallerRegistry) { + super(unmarshallerRegistry); + } + + private Builder() { + } + + public Builder payloadUnmarshaller(MarshallingType marshallingType, + JsonUnmarshaller marshaller) { + register(MarshallLocation.PAYLOAD, marshallingType, marshaller); + return this; + } + + public Builder headerUnmarshaller(MarshallingType marshallingType, + JsonUnmarshaller marshaller) { + register(MarshallLocation.HEADER, marshallingType, marshaller); + return this; + } + + public Builder statusCodeUnmarshaller(MarshallingType marshallingType, + JsonUnmarshaller marshaller) { + register(MarshallLocation.STATUS_CODE, marshallingType, marshaller); + return this; + } + + /** + * @return An immutable {@link DefaultJsonUnmarshallerRegistry} object. + */ + public DefaultJsonUnmarshallerRegistry build() { + return new DefaultJsonUnmarshallerRegistry(this); + } + } +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultProtocolUnmarshallDependencies.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultProtocolUnmarshallDependencies.java new file mode 100644 index 000000000000..46e027269abc --- /dev/null +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/DefaultProtocolUnmarshallDependencies.java @@ -0,0 +1,94 @@ +/* + * 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.protocols.json.internal.unmarshall; + +import java.util.Map; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory; +import software.amazon.awssdk.utils.Validate; + +@SdkInternalApi +public final class DefaultProtocolUnmarshallDependencies implements ProtocolUnmarshallDependencies { + private final JsonUnmarshallerRegistry jsonUnmarshallerRegistry; + private final JsonValueNodeFactory nodeValueFactory; + private final Map timestampFormats; + private final JsonFactory jsonFactory; + + private DefaultProtocolUnmarshallDependencies(Builder builder) { + this.jsonUnmarshallerRegistry = Validate.notNull(builder.jsonUnmarshallerRegistry, "jsonUnmarshallerRegistry"); + this.nodeValueFactory = Validate.notNull(builder.nodeValueFactory, "nodeValueFactory"); + this.timestampFormats = Validate.notNull(builder.timestampFormats, "timestampFormats"); + this.jsonFactory = Validate.notNull(builder.jsonFactory, "jsonFactory"); + } + + @Override + public JsonUnmarshallerRegistry jsonUnmarshallerRegistry() { + return jsonUnmarshallerRegistry; + } + + @Override + public JsonValueNodeFactory nodeValueFactory() { + return nodeValueFactory; + } + + @Override + public Map timestampFormats() { + return timestampFormats; + } + + @Override + public JsonFactory jsonFactory() { + return jsonFactory; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private JsonUnmarshallerRegistry jsonUnmarshallerRegistry; + private JsonValueNodeFactory nodeValueFactory; + private Map timestampFormats; + private JsonFactory jsonFactory; + + public Builder jsonUnmarshallerRegistry(JsonUnmarshallerRegistry jsonUnmarshallerRegistry) { + this.jsonUnmarshallerRegistry = jsonUnmarshallerRegistry; + return this; + } + + public Builder nodeValueFactory(JsonValueNodeFactory nodeValueFactory) { + this.nodeValueFactory = nodeValueFactory; + return this; + } + + public Builder timestampFormats(Map timestampFormats) { + this.timestampFormats = timestampFormats; + return this; + } + + public Builder jsonFactory(JsonFactory jsonFactory) { + this.jsonFactory = jsonFactory; + return this; + } + + public DefaultProtocolUnmarshallDependencies build() { + return new DefaultProtocolUnmarshallDependencies(this); + } + } +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java index b9f25716c241..b4121852f332 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java @@ -18,15 +18,14 @@ import static software.amazon.awssdk.protocols.core.StringToValueConverter.TO_SDK_BYTES; import java.io.IOException; -import java.math.BigDecimal; import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.ThreadSafe; import software.amazon.awssdk.core.SdkBytes; @@ -41,48 +40,73 @@ import software.amazon.awssdk.core.traits.TimestampFormatTrait; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.SdkHttpFullResponse; -import software.amazon.awssdk.protocols.core.NumberToInstant; import software.amazon.awssdk.protocols.core.StringToInstant; import software.amazon.awssdk.protocols.core.StringToValueConverter; +import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory; import software.amazon.awssdk.protocols.json.internal.MarshallerUtil; import software.amazon.awssdk.protocols.json.internal.unmarshall.document.DocumentUnmarshaller; import software.amazon.awssdk.protocols.jsoncore.JsonNode; import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.utils.Lazy; import software.amazon.awssdk.utils.builder.Buildable; /** - * Unmarshaller implementation for both JSON RPC and REST JSON services. This class is thread-safe and it is - * recommended to reuse a single instance for best performance. + * Unmarshaller implementation for both JSON RPC and REST JSON services. This class is thread-safe and it is recommended to reuse + * a single instance for best performance. */ @SdkInternalApi @ThreadSafe -public final class JsonProtocolUnmarshaller { - - public final StringToValueConverter.StringToValue instantStringToValue; - - private final NumberToInstant numberToInstant; +public class JsonProtocolUnmarshaller { + private static final Lazy DEFAULT_DEPENDENCIES = + new Lazy<>(JsonProtocolUnmarshaller::newProtocolUnmarshallDependencies); private final JsonUnmarshallerRegistry registry; - private final JsonNodeParser parser; private JsonProtocolUnmarshaller(Builder builder) { - this.parser = builder.parser; - this.instantStringToValue = StringToInstant.create(builder.defaultTimestampFormats.isEmpty() ? - new EnumMap<>(MarshallLocation.class) : - new EnumMap<>(builder.defaultTimestampFormats)); - this.numberToInstant = NumberToInstant.create(builder.defaultTimestampFormats.isEmpty() ? - new EnumMap<>(MarshallLocation.class) : - new EnumMap<>(builder.defaultTimestampFormats)); - this.registry = createUnmarshallerRegistry(instantStringToValue, numberToInstant); + ProtocolUnmarshallDependencies dependencies = builder.protocolUnmarshallDependencies; + this.parser = createParser(builder, dependencies); + this.registry = dependencies.jsonUnmarshallerRegistry(); } - private static JsonUnmarshallerRegistry createUnmarshallerRegistry( - StringToValueConverter.StringToValue instantStringToValue, - NumberToInstant numberToInstant - ) { + private JsonNodeParser createParser(Builder builder, ProtocolUnmarshallDependencies dependencies) { + if (builder.parser != null) { + return parser; + } + return JsonNodeParser + .builder() + .jsonFactory(dependencies.jsonFactory()) + .jsonValueNodeFactory(dependencies.nodeValueFactory()) + .build(); + } + + public static DefaultProtocolUnmarshallDependencies defaultProtocolUnmarshallDependencies() { + return DEFAULT_DEPENDENCIES.getValue(); + } + + public static DefaultProtocolUnmarshallDependencies newProtocolUnmarshallDependencies() { + return DefaultProtocolUnmarshallDependencies.builder() + .jsonUnmarshallerRegistry(defaultJsonUnmarshallerRegistry()) + .nodeValueFactory(JsonValueNodeFactory.DEFAULT) + .timestampFormats(defaultFormats()) + .jsonFactory(AwsStructuredPlainJsonFactory.SDK_JSON_FACTORY.getJsonFactory()) + .build(); + } - return JsonUnmarshallerRegistry + private static Map defaultFormats() { + Map formats = new EnumMap<>(MarshallLocation.class); + formats.put(MarshallLocation.HEADER, TimestampFormatTrait.Format.RFC_822); + formats.put(MarshallLocation.PAYLOAD, TimestampFormatTrait.Format.UNIX_TIMESTAMP); + return Collections.unmodifiableMap(formats); + } + + private static JsonUnmarshallerRegistry defaultJsonUnmarshallerRegistry() { + return timestampFormatRegistryFactory(defaultFormats()); + } + + public static DefaultJsonUnmarshallerRegistry createSharedRegistry() { + return DefaultJsonUnmarshallerRegistry .builder() .statusCodeUnmarshaller(MarshallingType.INTEGER, (context, json, f) -> context.response().statusCode()) .headerUnmarshaller(MarshallingType.STRING, HeaderUnmarshaller.STRING) @@ -91,34 +115,25 @@ private static JsonUnmarshallerRegistry createUnmarshallerRegistry( .headerUnmarshaller(MarshallingType.SHORT, HeaderUnmarshaller.SHORT) .headerUnmarshaller(MarshallingType.DOUBLE, HeaderUnmarshaller.DOUBLE) .headerUnmarshaller(MarshallingType.BOOLEAN, HeaderUnmarshaller.BOOLEAN) - .headerUnmarshaller(MarshallingType.INSTANT, HeaderUnmarshaller.createInstantHeaderUnmarshaller(instantStringToValue)) .headerUnmarshaller(MarshallingType.FLOAT, HeaderUnmarshaller.FLOAT) .headerUnmarshaller(MarshallingType.LIST, HeaderUnmarshaller.LIST) .payloadUnmarshaller(MarshallingType.STRING, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_STRING)) - .payloadUnmarshaller(MarshallingType.INTEGER, forEmbeddable(Number.class, Number::intValue, - StringToValueConverter.TO_INTEGER)) - .payloadUnmarshaller(MarshallingType.LONG, forEmbeddable(Number.class, Number::longValue, - StringToValueConverter.TO_LONG)) - .payloadUnmarshaller(MarshallingType.BYTE, forEmbeddable(Number.class, Number::byteValue, - StringToValueConverter.TO_BYTE)) - .payloadUnmarshaller(MarshallingType.SHORT, forEmbeddable(Number.class, Number::shortValue, - StringToValueConverter.TO_SHORT)) - .payloadUnmarshaller(MarshallingType.FLOAT, forEmbeddable(Number.class, Number::floatValue, - StringToValueConverter.TO_FLOAT)) - .payloadUnmarshaller(MarshallingType.DOUBLE, forEmbeddable(Number.class, Number::doubleValue, - StringToValueConverter.TO_DOUBLE)) - .payloadUnmarshaller(MarshallingType.BIG_DECIMAL, forEmbeddable(BigDecimal.class, - StringToValueConverter.TO_BIG_DECIMAL)) - .payloadUnmarshaller(MarshallingType.BOOLEAN, forEmbeddable(Boolean.class, StringToValueConverter.TO_BOOLEAN)) + .payloadUnmarshaller(MarshallingType.INTEGER, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_INTEGER)) + .payloadUnmarshaller(MarshallingType.LONG, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_LONG)) + .payloadUnmarshaller(MarshallingType.BYTE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_BYTE)) + .payloadUnmarshaller(MarshallingType.SHORT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_SHORT)) + .payloadUnmarshaller(MarshallingType.FLOAT, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_FLOAT)) + .payloadUnmarshaller(MarshallingType.DOUBLE, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_DOUBLE)) + .payloadUnmarshaller(MarshallingType.BIG_DECIMAL, new SimpleTypeJsonUnmarshaller<>( + StringToValueConverter.TO_BIG_DECIMAL)) + .payloadUnmarshaller(MarshallingType.BOOLEAN, new SimpleTypeJsonUnmarshaller<>(StringToValueConverter.TO_BOOLEAN)) .payloadUnmarshaller(MarshallingType.SDK_BYTES, JsonProtocolUnmarshaller::unmarshallSdkBytes) - .payloadUnmarshaller(MarshallingType.INSTANT, new SimpleTypeInstantJsonUnmarshaller<>(instantStringToValue, - numberToInstant)) .payloadUnmarshaller(MarshallingType.SDK_POJO, JsonProtocolUnmarshaller::unmarshallStructured) .payloadUnmarshaller(MarshallingType.LIST, JsonProtocolUnmarshaller::unmarshallList) .payloadUnmarshaller(MarshallingType.MAP, JsonProtocolUnmarshaller::unmarshallMap) .payloadUnmarshaller(MarshallingType.DOCUMENT, JsonProtocolUnmarshaller::unmarshallDocument) - .build(); + .build(); } private static SdkBytes unmarshallSdkBytes(JsonUnmarshallerContext context, @@ -163,12 +178,14 @@ private static Document getDocumentFromJsonContent(JsonNode jsonContent) { if (jsonContent == null || jsonContent.isNull()) { return null; } + SdkField valueInfo = field.getTrait(MapTrait.class).valueFieldInfo(); - Map map = new HashMap<>(); - jsonContent.asObject().forEach((fieldName, value) -> { - JsonUnmarshaller unmarshaller = context.getUnmarshaller(valueInfo.location(), valueInfo.marshallingType()); - map.put(fieldName, unmarshaller.unmarshall(context, value, valueInfo)); - }); + JsonUnmarshaller unmarshaller = context.getUnmarshaller(valueInfo.location(), valueInfo.marshallingType()); + Map asObject = jsonContent.asObject(); + Map map = new HashMap<>(asObject.size()); + for (Map.Entry kvp : asObject.entrySet()) { + map.put(kvp.getKey(), unmarshaller.unmarshall(context, kvp.getValue(), valueInfo)); + } return map; } @@ -176,15 +193,16 @@ private static List unmarshallList(JsonUnmarshallerContext context, JsonNode if (jsonContent == null || jsonContent.isNull()) { return null; } - return jsonContent.asArray() - .stream() - .map(item -> { - SdkField memberInfo = field.getTrait(ListTrait.class).memberFieldInfo(); - JsonUnmarshaller unmarshaller = context.getUnmarshaller(memberInfo.location(), - memberInfo.marshallingType()); - return unmarshaller.unmarshall(context, item, memberInfo); - }) - .collect(Collectors.toList()); + + SdkField memberInfo = field.getTrait(ListTrait.class).memberFieldInfo(); + List asArray = jsonContent.asArray(); + List result = new ArrayList<>(asArray.size()); + for (JsonNode node : asArray) { + JsonUnmarshaller unmarshaller = context.getUnmarshaller(memberInfo.location(), + memberInfo.marshallingType()); + result.add(unmarshaller.unmarshall(context, node, memberInfo)); + } + return result; } private static class SimpleTypeJsonUnmarshaller implements JsonUnmarshaller { @@ -203,116 +221,23 @@ public T unmarshall(JsonUnmarshallerContext context, } } - private static class EmbeddableTypeTransformingJsonUnmarshaller implements JsonUnmarshaller { - - private final StringToValueConverter.StringToValue stringToValue; - private final Class embeddedType; - private final Function typeConverter; - - private EmbeddableTypeTransformingJsonUnmarshaller( - Class embeddedType, - Function typeConverter, - StringToValueConverter.StringToValue stringToValue - ) { - this.stringToValue = stringToValue; - this.typeConverter = typeConverter; - this.embeddedType = embeddedType; - } - - @Override - public T unmarshall(JsonUnmarshallerContext context, - JsonNode jsonContent, - SdkField field) { - if (jsonContent == null || jsonContent.isNull()) { - return null; - } - String text = null; - if (jsonContent.isEmbeddedObject()) { - Object embedded = jsonContent.asEmbeddedObject(); - if (embedded == null) { - return null; - } - if (embeddedType.isAssignableFrom(embedded.getClass())) { - return typeConverter.apply((V) embedded); - } - // Fallback in case that the embedded object is not what - // we were looking for. - text = embedded.toString(); - } - if (text == null) { - text = jsonContent.text(); - } - return stringToValue.convert(text, field); - } - } - - private static class SimpleTypeInstantJsonUnmarshaller implements JsonUnmarshaller { - - private final StringToValueConverter.StringToValue stringToValue; - private final NumberToInstant numberToInstant; - - private SimpleTypeInstantJsonUnmarshaller( - StringToValueConverter.StringToValue stringToValue, - NumberToInstant numberToInstant - ) { - this.stringToValue = stringToValue; - this.numberToInstant = numberToInstant; - } - - @Override - public T unmarshall(JsonUnmarshallerContext context, - JsonNode jsonContent, - SdkField field) { - if (jsonContent == null || jsonContent.isNull()) { - return null; - } - String text = null; - if (jsonContent.isEmbeddedObject()) { - Object embedded = jsonContent.asEmbeddedObject(); - if (embedded == null) { - return null; - } - if (Number.class.isAssignableFrom(embedded.getClass())) { - return (T) numberToInstant.convert((Number) embedded, (SdkField) field); - } - // Fallback in case that the embedded object is not what - // we were looking for. - text = embedded.toString(); - } - if (text == null) { - text = jsonContent.text(); - } - return stringToValue.convert(text, field); - } - } - - private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( - Class embeddedType, - Function transformer, - StringToValueConverter.StringToValue stringToValue - ) { - return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, transformer, stringToValue); - } - - private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( - Class embeddedType, - StringToValueConverter.StringToValue stringToValue - ) { - return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, Function.identity(), stringToValue); - } - public TypeT unmarshall(SdkPojo sdkPojo, - SdkHttpFullResponse response) throws IOException { + SdkHttpFullResponse response) throws IOException { JsonNode jsonNode = hasJsonPayload(sdkPojo, response) ? parser.parse(response.content().get()) : null; return unmarshall(sdkPojo, response, jsonNode); } private boolean hasJsonPayload(SdkPojo sdkPojo, SdkHttpFullResponse response) { - return sdkPojo.sdkFields() - .stream() - .anyMatch(f -> isPayloadMemberOnUnmarshall(f) && !isExplicitBlobPayloadMember(f) - && !isExplicitStringPayloadMember(f)) - && response.content().isPresent(); + if (!response.content().isPresent()) { + return false; + } + for (SdkField field : sdkPojo.sdkFields()) { + if (isPayloadMemberOnUnmarshall(field) && !isExplicitBlobPayloadMember(field) + && !isExplicitStringPayloadMember(field)) { + return true; + } + } + return false; } private boolean isExplicitBlobPayloadMember(SdkField f) { @@ -332,8 +257,8 @@ private boolean isPayloadMemberOnUnmarshall(SdkField f) { } public TypeT unmarshall(SdkPojo sdkPojo, - SdkHttpFullResponse response, - JsonNode jsonContent) { + SdkHttpFullResponse response, + JsonNode jsonContent) { JsonUnmarshallerContext context = JsonUnmarshallerContext.builder() .unmarshallerRegistry(registry) .response(response) @@ -387,13 +312,33 @@ public static Builder builder() { return new Builder(); } + /** + * Creates the default {@link JsonProtocolUnmarshaller}, which parses {@link Instant} using the default formats passed in. + */ + public static JsonUnmarshallerRegistry timestampFormatRegistryFactory( + Map formats + ) { + StringToValueConverter.StringToValue instantStringToValue = StringToInstant + .create(formats.isEmpty() ? + new EnumMap<>(MarshallLocation.class) : + new EnumMap<>(formats)); + + return createSharedRegistry() + .toBuilder() + .headerUnmarshaller(MarshallingType.INSTANT, + HeaderUnmarshaller.createInstantHeaderUnmarshaller(instantStringToValue)) + .payloadUnmarshaller(MarshallingType.INSTANT, + new SimpleTypeJsonUnmarshaller<>(instantStringToValue)) + .build(); + } + /** * Builder for {@link JsonProtocolUnmarshaller}. */ public static final class Builder { private JsonNodeParser parser; - private Map defaultTimestampFormats; + private ProtocolUnmarshallDependencies protocolUnmarshallDependencies; private Builder() { } @@ -410,12 +355,25 @@ public Builder parser(JsonNodeParser parser) { /** * @param formats The default timestamp formats for each location in the HTTP response. * @return This builder for method chaining. + * @deprecated Use instead {@link #protocolUnmarshallDependencies} */ + @Deprecated public Builder defaultTimestampFormats(Map formats) { - this.defaultTimestampFormats = formats; return this; } + /** + * @param protocolUnmarshallDependencies The default instant registry unmarshaller factory. + * @return This builder for method chaining. + */ + public Builder protocolUnmarshallDependencies( + ProtocolUnmarshallDependencies protocolUnmarshallDependencies + ) { + this.protocolUnmarshallDependencies = protocolUnmarshallDependencies; + return this; + } + + /** * @return New instance of {@link JsonProtocolUnmarshaller}. */ @@ -423,5 +381,4 @@ public JsonProtocolUnmarshaller build() { return new JsonProtocolUnmarshaller(this); } } - } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonUnmarshallerRegistry.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonUnmarshallerRegistry.java index ff461163f5d3..dbbc56a456a4 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonUnmarshallerRegistry.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonUnmarshallerRegistry.java @@ -18,61 +18,15 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.protocol.MarshallingType; -import software.amazon.awssdk.protocols.core.AbstractMarshallingRegistry; /** * Registry of {@link JsonUnmarshaller} implementations by location and type. */ @SdkInternalApi -final class JsonUnmarshallerRegistry extends AbstractMarshallingRegistry { - - private JsonUnmarshallerRegistry(Builder builder) { - super(builder); - } - - @SuppressWarnings("unchecked") - public JsonUnmarshaller getUnmarshaller(MarshallLocation marshallLocation, MarshallingType marshallingType) { - return (JsonUnmarshaller) get(marshallLocation, marshallingType); - } - - /** - * @return Builder instance to construct a {@link JsonUnmarshallerRegistry}. - */ - public static Builder builder() { - return new Builder(); - } +public interface JsonUnmarshallerRegistry { /** - * Builder for a {@link JsonUnmarshallerRegistry}. + * Returns the unmarshaller for the given location and type. Throws an exception if no unmarshaller is found. */ - public static final class Builder extends AbstractMarshallingRegistry.Builder { - - private Builder() { - } - - public Builder payloadUnmarshaller(MarshallingType marshallingType, - JsonUnmarshaller marshaller) { - register(MarshallLocation.PAYLOAD, marshallingType, marshaller); - return this; - } - - public Builder headerUnmarshaller(MarshallingType marshallingType, - JsonUnmarshaller marshaller) { - register(MarshallLocation.HEADER, marshallingType, marshaller); - return this; - } - - public Builder statusCodeUnmarshaller(MarshallingType marshallingType, - JsonUnmarshaller marshaller) { - register(MarshallLocation.STATUS_CODE, marshallingType, marshaller); - return this; - } - - /** - * @return An immutable {@link JsonUnmarshallerRegistry} object. - */ - public JsonUnmarshallerRegistry build() { - return new JsonUnmarshallerRegistry(this); - } - } + JsonUnmarshaller getUnmarshaller(MarshallLocation marshallLocation, MarshallingType marshallingType); } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/ProtocolUnmarshallDependencies.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/ProtocolUnmarshallDependencies.java new file mode 100644 index 000000000000..1b45aa36b1e7 --- /dev/null +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/ProtocolUnmarshallDependencies.java @@ -0,0 +1,52 @@ +/* + * 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.protocols.json.internal.unmarshall; + +import java.util.Map; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory; + +@SdkInternalApi +public interface ProtocolUnmarshallDependencies { + + /** + * Used for unmarshalling. This registry is used to lookup an unmarshaller for a given location and marshalling type. + * @see JsonUnmarshaller + * @see JsonUnmarshallerContext#getUnmarshaller(MarshallLocation, MarshallingType) + */ + JsonUnmarshallerRegistry jsonUnmarshallerRegistry(); + + /** + * Used for parsing. This factory knows how to convert the state of the parser into {@link JsonNode} instances that are + * used during unmarshalling. + */ + JsonValueNodeFactory nodeValueFactory(); + + /** + * Used to expose this data through the interface. + */ + Map timestampFormats(); + + /** + * Used to parse JSON using Jackson. + */ + JsonFactory jsonFactory(); +} diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/UnmarshallerRegistryFactory.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/UnmarshallerRegistryFactory.java new file mode 100644 index 000000000000..518f32fecb15 --- /dev/null +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/UnmarshallerRegistryFactory.java @@ -0,0 +1,31 @@ +/* + * 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.protocols.json.internal.unmarshall; + +import software.amazon.awssdk.annotations.SdkInternalApi; + +/** + * Interface used to create an {@link UnmarshallerRegistryFactory} that will unmarshall using the given default formats for each + * of the locations in the formats map. + */ +@SdkInternalApi +public interface UnmarshallerRegistryFactory { + + /** + * Returns a unmarshaller registry that uses the default timestamp formats passed in. + */ + JsonUnmarshallerRegistry get(); +} diff --git a/core/protocols/aws-json-protocol/src/test/java/software/amazon/awssdk/protocols/json/FaultStatusCodeMappingTest.java b/core/protocols/aws-json-protocol/src/test/java/software/amazon/awssdk/protocols/json/FaultStatusCodeMappingTest.java index fc41b25c107f..a6aeeec2e0e1 100644 --- a/core/protocols/aws-json-protocol/src/test/java/software/amazon/awssdk/protocols/json/FaultStatusCodeMappingTest.java +++ b/core/protocols/aws-json-protocol/src/test/java/software/amazon/awssdk/protocols/json/FaultStatusCodeMappingTest.java @@ -108,6 +108,7 @@ private static AwsJsonProtocolErrorUnmarshaller makeUnmarshaller(List "Some server error") diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java index 48b04f6c6a24..e7fe57a7e856 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java @@ -105,6 +105,11 @@ public abstract static class Builder { protected Builder() { } + protected Builder(AbstractMarshallingRegistry marshallingRegistry) { + deepCopy(this.registry, marshallingRegistry.registry); + this.marshallingTypes.addAll(marshallingRegistry.marshallingTypes); + } + protected Builder register(MarshallLocation marshallLocation, MarshallingType marshallingType, Object marshaller) { @@ -114,4 +119,16 @@ protected Builder register(MarshallLocation marshallLocation, return this; } } + + /** + * Copies the map values from source to target making sure to create a new copy that can be owned by the source. + */ + private static void deepCopy( + Map> target, + Map> source + ) { + for (Map.Entry> sourceKvp : source.entrySet()) { + target.computeIfAbsent(sourceKvp.getKey(), (x) -> new HashMap<>()).putAll(sourceKvp.getValue()); + } + } } diff --git a/core/protocols/smithy-rpcv2-protocol/pom.xml b/core/protocols/smithy-rpcv2-protocol/pom.xml index 7c5507653219..b3c61e4a2de9 100644 --- a/core/protocols/smithy-rpcv2-protocol/pom.xml +++ b/core/protocols/smithy-rpcv2-protocol/pom.xml @@ -61,6 +61,16 @@ json-utils ${awsjavasdk.version} + + software.amazon.awssdk + utils + ${awsjavasdk.version} + + + software.amazon.awssdk + protocol-core + ${awsjavasdk.version} + org.junit.jupiter junit-jupiter diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java index 0cb8d6fcd239..8498e574efda 100644 --- a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/SmithyRpcV2CborProtocolFactory.java @@ -24,9 +24,13 @@ import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.JsonContentTypeResolver; import software.amazon.awssdk.protocols.json.StructuredJsonFactory; -import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.protocols.json.internal.unmarshall.DefaultProtocolUnmarshallDependencies; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonUnmarshallerRegistry; +import software.amazon.awssdk.protocols.json.internal.unmarshall.ProtocolUnmarshallDependencies; +import software.amazon.awssdk.protocols.rpcv2.internal.SdkRpcV2CborUnmarshaller; import software.amazon.awssdk.protocols.rpcv2.internal.SdkRpcV2CborValueNodeFactory; import software.amazon.awssdk.protocols.rpcv2.internal.SdkStructuredRpcV2CborFactory; +import software.amazon.awssdk.utils.Lazy; /** * Protocol factory for RPCv2 CBOR protocol. @@ -34,6 +38,9 @@ @SdkProtectedApi public final class SmithyRpcV2CborProtocolFactory extends BaseAwsJsonProtocolFactory { + private static final Lazy DEPENDENCIES = + new Lazy<>(SmithyRpcV2CborProtocolFactory::newProtocolUnmarshallDependencies); + /** * Content type resolver implementation for RPC_V2_CBOR enabled services. */ @@ -67,21 +74,39 @@ protected Map getDefaultTimestamp return LazyHolder.DEFAULT_TIMESTAMP_FORMATS; } - @Override - public JsonValueNodeFactory getJsonValueNodeFactory() { - return SdkRpcV2CborValueNodeFactory.INSTANCE; - } - public static Builder builder() { return new Builder(); } + public static ProtocolUnmarshallDependencies defaultProtocolUnmarshallDependencies() { + return DEPENDENCIES.getValue(); + } + + public static DefaultProtocolUnmarshallDependencies newProtocolUnmarshallDependencies() { + return DefaultProtocolUnmarshallDependencies + .builder() + .jsonUnmarshallerRegistry(defaultCborUnmarshallerRegistry()) + .nodeValueFactory(SdkRpcV2CborValueNodeFactory.INSTANCE) + .timestampFormats(defaultFormats()) + .jsonFactory(SdkStructuredRpcV2CborFactory.SDK_CBOR_FACTORY.getJsonFactory()) + .build(); + } + + private static Map defaultFormats() { + return LazyHolder.DEFAULT_TIMESTAMP_FORMATS; + } + + private static JsonUnmarshallerRegistry defaultCborUnmarshallerRegistry() { + return SdkRpcV2CborUnmarshaller.timestampFormatRegistryFactory(defaultFormats()); + } + /** * Builder for {@link SmithyRpcV2CborProtocolFactory}. */ public static final class Builder extends BaseAwsJsonProtocolFactory.Builder { private Builder() { + protocolUnmarshallDependencies(SmithyRpcV2CborProtocolFactory::defaultProtocolUnmarshallDependencies); } public SmithyRpcV2CborProtocolFactory build() { @@ -101,7 +126,6 @@ static Map createDefaultTimestamp Map formats = new EnumMap<>(MarshallLocation.class); formats.put(MarshallLocation.PAYLOAD, TimestampFormatTrait.Format.UNIX_TIMESTAMP); return Collections.unmodifiableMap(formats); - } } } diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborUnmarshaller.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborUnmarshaller.java new file mode 100644 index 000000000000..5e35c03ba9dd --- /dev/null +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborUnmarshaller.java @@ -0,0 +1,202 @@ +/* + * 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.protocols.rpcv2.internal; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Function; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.SdkField; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.protocols.core.NumberToInstant; +import software.amazon.awssdk.protocols.core.StringToInstant; +import software.amazon.awssdk.protocols.core.StringToValueConverter; +import software.amazon.awssdk.protocols.json.internal.unmarshall.DefaultJsonUnmarshallerRegistry; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonUnmarshaller; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonUnmarshallerContext; +import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonUnmarshallerRegistry; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.internal.EmbeddedObjectJsonNode; + +/** + * Unmarshalling support for the Smithy RPCv2 protocol. + */ +@SdkInternalApi +public final class SdkRpcV2CborUnmarshaller { + + private SdkRpcV2CborUnmarshaller() { + } + + public static JsonUnmarshallerRegistry timestampFormatRegistryFactory( + Map formats + ) { + DefaultJsonUnmarshallerRegistry.Builder builder = + JsonProtocolUnmarshaller.createSharedRegistry() + .toBuilder(); + StringToValueConverter.StringToValue instantStringToValue = StringToInstant + .create(formats.isEmpty() ? + new EnumMap<>(MarshallLocation.class) : + new EnumMap<>(formats)); + + NumberToInstant instantNumberToValue = NumberToInstant + .create(formats.isEmpty() ? + new EnumMap<>(MarshallLocation.class) : + new EnumMap<>(formats)); + + SimpleTypeInstantJsonUnmarshaller payloadUnmarshaller = + new SimpleTypeInstantJsonUnmarshaller<>(instantStringToValue, instantNumberToValue); + + builder.payloadUnmarshaller(MarshallingType.INSTANT, payloadUnmarshaller); + return setPayloadOverrides(builder).build(); + } + + /** + * Creates an unmarshalling registry that knows how to read embedded values from the parse result. + */ + public static DefaultJsonUnmarshallerRegistry.Builder setPayloadOverrides(DefaultJsonUnmarshallerRegistry.Builder builder) { + builder.payloadUnmarshaller(MarshallingType.INTEGER, forEmbeddable(Number.class, Number::intValue, + StringToValueConverter.TO_INTEGER)) + .payloadUnmarshaller(MarshallingType.LONG, forEmbeddable(Number.class, Number::longValue, + StringToValueConverter.TO_LONG)) + .payloadUnmarshaller(MarshallingType.BYTE, forEmbeddable(Number.class, Number::byteValue, + StringToValueConverter.TO_BYTE)) + .payloadUnmarshaller(MarshallingType.SHORT, forEmbeddable(Number.class, Number::shortValue, + StringToValueConverter.TO_SHORT)) + .payloadUnmarshaller(MarshallingType.FLOAT, forEmbeddable(Number.class, Number::floatValue, + StringToValueConverter.TO_FLOAT)) + .payloadUnmarshaller(MarshallingType.DOUBLE, forEmbeddable(Number.class, Number::doubleValue, + StringToValueConverter.TO_DOUBLE)) + .payloadUnmarshaller(MarshallingType.BIG_DECIMAL, forEmbeddable(BigDecimal.class, + StringToValueConverter.TO_BIG_DECIMAL)) + .payloadUnmarshaller(MarshallingType.BOOLEAN, forEmbeddable(Boolean.class, + StringToValueConverter.TO_BOOLEAN)); + return builder; + } + + /** + * Creates an unmarshaller that expects the {@code embeddedType} from an {@link EmbeddedObjectJsonNode}. If the node given for + * unmarshalling is of this type, and the type of its value is instance of {@code embeddedType}, then the {@code transformer} + * is used to convert the expected type into the target type. For instance, to read an integer from an + * {@link EmbeddedObjectJsonNode} the caller will use. + *
+     *     forEmbeddable(Number.class, Number::intValue, StringToValueConverter.TO_INTEGER)
+     * 
+ * Using Java numbers to convert to other numbers gives a seamless way to upcast when the number is encoded using a smaller + * type because those fit. The last argument allows a final fallback to parse from a string value. + */ + private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( + Class embeddedType, + Function transformer, + StringToValueConverter.StringToValue stringToValue + ) { + return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, transformer, stringToValue); + } + + private static EmbeddableTypeTransformingJsonUnmarshaller forEmbeddable( + Class embeddedType, + StringToValueConverter.StringToValue stringToValue + ) { + return new EmbeddableTypeTransformingJsonUnmarshaller<>(embeddedType, Function.identity(), stringToValue); + } + + private static class EmbeddableTypeTransformingJsonUnmarshaller implements JsonUnmarshaller { + + private final StringToValueConverter.StringToValue stringToValue; + private final Class embeddedType; + private final Function typeConverter; + + private EmbeddableTypeTransformingJsonUnmarshaller( + Class embeddedType, + Function typeConverter, + StringToValueConverter.StringToValue stringToValue + ) { + this.stringToValue = stringToValue; + this.typeConverter = typeConverter; + this.embeddedType = embeddedType; + } + + @Override + public T unmarshall(JsonUnmarshallerContext context, + JsonNode jsonContent, + SdkField field) { + if (jsonContent == null || jsonContent.isNull()) { + return null; + } + String text = null; + if (jsonContent.isEmbeddedObject()) { + Object embedded = jsonContent.asEmbeddedObject(); + if (embedded == null) { + return null; + } + if (embeddedType.isAssignableFrom(embedded.getClass())) { + return typeConverter.apply((V) embedded); + } + // Fallback in case that the embedded object is not what + // we were looking for. + text = embedded.toString(); + } + if (text == null) { + text = jsonContent.text(); + } + return stringToValue.convert(text, field); + } + } + + private static class SimpleTypeInstantJsonUnmarshaller implements JsonUnmarshaller { + + private final StringToValueConverter.StringToValue stringToValue; + private final NumberToInstant numberToInstant; + + private SimpleTypeInstantJsonUnmarshaller( + StringToValueConverter.StringToValue stringToValue, + NumberToInstant numberToInstant + ) { + this.stringToValue = stringToValue; + this.numberToInstant = numberToInstant; + } + + @Override + public T unmarshall(JsonUnmarshallerContext context, + JsonNode jsonContent, + SdkField field) { + if (jsonContent == null || jsonContent.isNull()) { + return null; + } + String text = null; + if (jsonContent.isEmbeddedObject()) { + Object embedded = jsonContent.asEmbeddedObject(); + if (embedded == null) { + return null; + } + if (Number.class.isAssignableFrom(embedded.getClass())) { + return (T) numberToInstant.convert((Number) embedded, (SdkField) field); + } + // Fallback in case that the embedded object is not what + // we were looking for. + text = embedded.toString(); + } + if (text == null) { + text = jsonContent.text(); + } + return stringToValue.convert(text, field); + } + } +} diff --git a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java index f85136221492..1600c72d5aa8 100644 --- a/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java +++ b/core/protocols/smithy-rpcv2-protocol/src/main/java/software/amazon/awssdk/protocols/rpcv2/internal/SdkRpcV2CborValueNodeFactory.java @@ -71,29 +71,14 @@ private JsonNode nodeForNumber(JsonParser parser, JsonToken token) throws IOExce case LONG: case FLOAT: case DOUBLE: - try { - Number javaNumber = parser.getNumberValue(); - return new EmbeddedObjectJsonNode(javaNumber); - } catch (Exception e) { - // ignored - } - break; + Number javaNumber = parser.getNumberValue(); + return new EmbeddedObjectJsonNode(javaNumber); case BIG_DECIMAL: - try { - BigDecimal bigDecimal = parser.getDecimalValue(); - return new EmbeddedObjectJsonNode(bigDecimal); - } catch (Exception e) { - // ignored - } - break; + BigDecimal bigDecimal = parser.getDecimalValue(); + return new EmbeddedObjectJsonNode(bigDecimal); case BIG_INTEGER: - try { - BigInteger bigInteger = parser.getBigIntegerValue(); - return new EmbeddedObjectJsonNode(bigInteger); - } catch (Exception e) { - // ignored - } - break; + BigInteger bigInteger = parser.getBigIntegerValue(); + return new EmbeddedObjectJsonNode(bigInteger); default: } return new NumberJsonNode(parser.getText()); diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/JsonTestUtils.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/JsonTestUtils.java new file mode 100644 index 000000000000..00f15f562881 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/JsonTestUtils.java @@ -0,0 +1,41 @@ +/* + * 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.enhanced.dynamodb; + +import java.util.ArrayList; +import java.util.List; +import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; + +public class JsonTestUtils { + + public static List toJsonNode(List documents) { + List list = new ArrayList<>(documents.size()); + for (EnhancedDocument document : documents) { + String toJson = document.toJson(); + JsonNode jsonNode = parseJson(toJson); + list.add(jsonNode); + } + return list; + } + + public static JsonNode parseJson(String json) { + JsonNodeParser parser = JsonNodeParser.create(); + return parser.parse(json); + } + +} diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicQueryTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicQueryTest.java index eeb82f12922c..7b5f1d602223 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicQueryTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicQueryTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider; +import static software.amazon.awssdk.enhanced.dynamodb.JsonTestUtils.toJsonNode; import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.numberValue; import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.stringValue; import static software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional.keyEqualTo; @@ -47,6 +48,7 @@ import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.EnhancedType; import software.amazon.awssdk.enhanced.dynamodb.Expression; +import software.amazon.awssdk.enhanced.dynamodb.JsonTestUtils; import software.amazon.awssdk.enhanced.dynamodb.Key; import software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName; import software.amazon.awssdk.enhanced.dynamodb.TableMetadata; @@ -59,10 +61,14 @@ import software.amazon.awssdk.enhanced.dynamodb.model.Page; import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable; import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.AttributeValue; import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest; import software.amazon.awssdk.services.dynamodb.model.Select; +import software.amazon.awssdk.thirdparty.jackson.core.JsonParser; +import software.amazon.awssdk.thirdparty.jackson.core.JsonToken; public class BasicQueryTest extends LocalDynamoDbSyncTestBase { private DynamoDbClient lowLevelClient; @@ -211,12 +217,13 @@ public void queryAllRecordsDefaultSettings_shortcutForm() { Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS.stream().map(i -> i - .toBuilder() - .attributeConverterProviders(new InnerAttribConverterProvider<>(), defaultProvider()) - .build() - .toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS.stream().map(i -> i + .toBuilder() + .attributeConverterProviders(new InnerAttribConverterProvider<>(), + defaultProvider()) + .build()) + .collect(Collectors.toList())))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -305,12 +312,12 @@ public void queryAllRecordsDefaultSettings_shortcutForm_viaItems() { PageIterable query = docMappedtable.query(keyEqualTo(k -> k.partitionValue("id-value"))); SdkIterable results = query.items(); - assertThat(results.stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS.stream().map(i -> i - .toBuilder() - .attributeConverterProviders(new InnerAttribConverterProvider<>(), defaultProvider()) - .build() - .toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(results.stream().collect(Collectors.toList())), + is(toJsonNode(DOCUMENTS.stream().map(i -> i + .toBuilder() + .attributeConverterProviders(new InnerAttribConverterProvider<>(), defaultProvider()) + .build()) + .collect(Collectors.toList())))); } @@ -337,10 +344,12 @@ public void queryAllRecordsWithFilter() { Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber("sort").intValue() <= 5) - .map(doc -> doc.toJson()) - .collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode( + DOCUMENTS_WITH_PROVIDERS.stream(). + filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber( + "sort").intValue() <= 5) + .collect(Collectors.toList())))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -387,10 +396,10 @@ public void queryBetween() { Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber("sort").intValue() <= 5) - .map(doc -> doc.toJson()) - .collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.stream() + .filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber("sort").intValue() <= 5) + .collect(Collectors.toList())))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -417,13 +426,13 @@ public void queryLimit() { Map expectedLastEvaluatedKey2 = new HashMap<>(); expectedLastEvaluatedKey2.put("id", stringValue("id-value")); expectedLastEvaluatedKey2.put("sort", numberValue(9)); - assertThat(page1.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(0, 5).stream().map( doc -> doc.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page1.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(0, 5)))); assertThat(page1.lastEvaluatedKey(), is(expectedLastEvaluatedKey1)); - assertThat(page2.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(5, 10).stream().map( doc -> doc.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page2.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(5, 10)))); assertThat(page2.lastEvaluatedKey(), is(expectedLastEvaluatedKey2)); - assertThat(page3.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), is(empty())); + assertThat(page3.items(), is(empty())); assertThat(page3.lastEvaluatedKey(), is(nullValue())); } @@ -461,8 +470,8 @@ public void queryExclusiveStartKey() { assertThat(results.hasNext(), is(true)); Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(doc -> doc.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(8, 10).stream().map(i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(8, 10)))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -479,8 +488,8 @@ public void queryExclusiveStartKey_viaItems() { .build()) .items(); - assertThat(results.stream().map(doc -> doc.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(8, 10).stream().map(i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(results.stream().collect(Collectors.toList())), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(8, 10)))); } @Test diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicScanTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicScanTest.java index 6f0b9284f58c..145a25ac917d 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicScanTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicScanTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider; +import static software.amazon.awssdk.enhanced.dynamodb.JsonTestUtils.toJsonNode; import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.numberValue; import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.stringValue; @@ -179,8 +180,8 @@ public void scanAllRecordsDefaultSettings() { Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(doc -> doc.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().map(i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -207,8 +208,8 @@ public void queryAllRecordsDefaultSettings_withProjection() { public void scanAllRecordsDefaultSettings_viaItems() { insertDocuments(); SdkIterable items = docMappedtable.scan(ScanEnhancedRequest.builder().limit(2).build()).items(); - assertThat(items.stream().map(i->i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().map(i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(items.stream().collect(Collectors.toList())), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS))); } @Test @@ -229,10 +230,11 @@ public void scanAllRecordsWithFilter() { Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber("sort").intValue() <= 5) - .map( j -> j.toJson()) - .collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS + .stream() + .filter(r -> r.getNumber("sort").intValue() >= 3 && r.getNumber("sort").intValue() <= 5) + .collect(Collectors.toList())))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -280,11 +282,11 @@ public void scanLimit() { Page page3 = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page1.items().stream().map( i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(0, 5).stream().map( i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page1.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(0, 5)))); assertThat(page1.lastEvaluatedKey(), is(getKeyMap(4))); - assertThat(page2.items().stream().map( i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(5, 10).stream().map( i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page2.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(5, 10)))); assertThat(page2.lastEvaluatedKey(), is(getKeyMap(9))); assertThat(page3.items(), is(empty())); @@ -295,9 +297,8 @@ public void scanLimit() { public void scanLimit_viaItems() { insertDocuments(); SdkIterable results = docMappedtable.scan(r -> r.limit(5)).items(); - assertThat(results.stream().map(i -> i.toJson()) - .collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.stream().map(i ->i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(results.stream().collect(Collectors.toList())), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS))); } @Test @@ -325,8 +326,8 @@ public void scanExclusiveStartKey() { assertThat(results.hasNext(), is(true)); Page page = results.next(); assertThat(results.hasNext(), is(false)); - assertThat(page.items().stream().map(i -> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(8, 10).stream().map( i -> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(page.items()), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(8, 10)))); assertThat(page.lastEvaluatedKey(), is(nullValue())); } @@ -335,8 +336,8 @@ public void scanExclusiveStartKey_viaItems() { insertDocuments(); SdkIterable results = docMappedtable.scan(r -> r.exclusiveStartKey(getKeyMap(7))).items(); - assertThat(results.stream().map( i-> i.toJson()).collect(Collectors.toList()), - is(DOCUMENTS_WITH_PROVIDERS.subList(8, 10).stream().map( i-> i.toJson()).collect(Collectors.toList()))); + assertThat(toJsonNode(results.stream().collect(Collectors.toList())), + is(toJsonNode(DOCUMENTS_WITH_PROVIDERS.subList(8, 10)))); } private Map getKeyMap(int sort) { diff --git a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java index 86a3ae0d6dd2..4eff341379ba 100644 --- a/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java +++ b/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/protocol/JsonCodec.java @@ -41,10 +41,8 @@ import software.amazon.awssdk.protocols.json.StructuredJsonFactory; import software.amazon.awssdk.protocols.json.internal.marshall.JsonProtocolMarshallerBuilder; import software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller; -import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; -import software.amazon.awssdk.protocols.jsoncore.JsonValueNodeFactory; +import software.amazon.awssdk.protocols.json.internal.unmarshall.ProtocolUnmarshallDependencies; import software.amazon.awssdk.protocols.rpcv2.SmithyRpcV2CborProtocolFactory; -import software.amazon.awssdk.protocols.rpcv2.internal.SdkRpcV2CborValueNodeFactory; import software.amazon.awssdk.utils.IoUtils; /** @@ -70,11 +68,7 @@ public SdkPojo unmarshall(AwsJsonProtocol protocol, SdkPojo pojo, byte[] bytes) JsonProtocolUnmarshaller unmarshaller = JsonProtocolUnmarshaller .builder() - .parser(JsonNodeParser.builder() - .jsonFactory(behavior.structuredJsonFactory().getJsonFactory()) - .jsonValueNodeFactory(behavior.jsonValueNodeFactory()) - .build()) - .defaultTimestampFormats(behavior.timestampFormats()) + .protocolUnmarshallDependencies(behavior.protocolUnmarshallDependencies()) .build(); SdkHttpFullResponse response = SdkHttpFullResponse .builder() @@ -143,6 +137,9 @@ enum ProtocolBehavior { .build(); Supplier structuredJsonFactory = getStructuredJsonFactory(factory); + ProtocolUnmarshallDependencies rpcv2Dependencies = SmithyRpcV2CborProtocolFactory + .defaultProtocolUnmarshallDependencies(); + @Override public AwsJsonProtocolMetadata protocolMetadata() { return metadata; @@ -154,10 +151,11 @@ public StructuredJsonFactory structuredJsonFactory() { } @Override - public JsonValueNodeFactory jsonValueNodeFactory() { - return SdkRpcV2CborValueNodeFactory.INSTANCE; + public ProtocolUnmarshallDependencies protocolUnmarshallDependencies() { + return rpcv2Dependencies; } + @Override public String contentType() { return "application/cbor"; @@ -189,6 +187,8 @@ public StructuredJsonFactory structuredJsonFactory() { ; private final AwsJsonProtocol protocol; + private final ProtocolUnmarshallDependencies dpendencies = JsonProtocolUnmarshaller + .defaultProtocolUnmarshallDependencies(); ProtocolBehavior(AwsJsonProtocol protocol) { this.protocol = protocol; @@ -202,12 +202,8 @@ public StructuredJsonFactory structuredJsonFactory() { throw new UnsupportedOperationException(); } - public JsonValueNodeFactory jsonValueNodeFactory() { - return JsonValueNodeFactory.DEFAULT; - } - - public Map timestampFormats() { - return TIMESTAMP_FORMATS; + public ProtocolUnmarshallDependencies protocolUnmarshallDependencies() { + return dpendencies; } public OperationInfo operationInfo() { From 9795f154b18281460c07f44e2b18dc0933408012 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Wed, 4 Sep 2024 14:05:10 -0700 Subject: [PATCH 12/14] Avoid growing copies of collections of known size (#5551) --- .../codegen/poet/model/MemberCopierSpec.java | 28 +++++++++++++------ .../codegen/poet/model/blobmaptypecopier.java | 2 +- .../poet/model/listofblobstypecopier.java | 5 +--- .../codegen/poet/model/listofenumscopier.java | 6 ++-- .../poet/model/listofintegerscopier.java | 5 +--- .../listoflistoflistofstringscopier.java | 11 +++----- .../poet/model/listoflistofstringscopier.java | 7 ++--- .../model/listofmapofenumtostringcopier.java | 12 ++++---- .../listofmapofstringtostructcopier.java | 18 ++++++------ .../model/listofmapstringtostringcopier.java | 4 +-- .../poet/model/listofsimplestructscopier.java | 6 ++-- .../poet/model/listofstringscopier.java | 5 +--- .../poet/model/mapofenumtoenumcopier.java | 6 ++-- .../model/mapofenumtolistofenumscopier.java | 12 ++++---- .../mapofenumtomapofstringtoenumcopier.java | 16 +++++------ .../model/mapofenumtosimplestructcopier.java | 10 +++---- .../poet/model/mapofenumtostringcopier.java | 6 ++-- .../poet/model/mapofstringtoenumcopier.java | 6 ++-- .../model/mapofstringtointegerlistcopier.java | 7 ++--- ...apofstringtolistoflistofstringscopier.java | 11 +++----- .../mapofstringtosimplestructcopier.java | 6 ++-- .../poet/model/mapofstringtostringcopier.java | 2 +- .../poet/model/recursivelisttypecopier.java | 6 ++-- .../poet/model/recursivemaptypecopier.java | 8 +++--- 24 files changed, 97 insertions(+), 108 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/MemberCopierSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/MemberCopierSpec.java index d716f96adaaa..ee0a13698ddd 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/MemberCopierSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/MemberCopierSpec.java @@ -269,18 +269,27 @@ private String copyMethodBody(CodeBlock.Builder code, BuilderTransform builderTr code.add("$T $N;", listType, outputVariableName) .add("if ($1N == null || $1N instanceof $2T) {", inputVariableName, SdkAutoConstructList.class) .add("$N = $T.getInstance();", outputVariableName, DefaultSdkAutoConstructList.class) - .add("} else {") - .add("$T $N = new $T<>();", listType, modifiableVariableName, ArrayList.class); + .add("} else {"); + String entryInputVariable = variableSource.getNew("entry"); - code.add("$N.forEach($N -> {", inputVariableName, entryInputVariable); - String entryOutputVariable = - copyMethodBody(code, builderTransform, variableSource, enumTransform, entryInputVariable, listEntryModel); + // Short-circuit, if the member is simple then we can directly use the constructor + // that takes a collection which should have a better performance characteristics. + boolean isMemberSimple = listEntryModel.isSimple() && listEntryModel.getEnumType() == null; + if (isMemberSimple) { + code.add("$T $N = new $T<>($N);", listType, modifiableVariableName, ArrayList.class, inputVariableName); + } else { + code.add("$T $N = new $T<>($N.size());", listType, modifiableVariableName, ArrayList.class, inputVariableName); + code.add("$N.forEach($N -> {", inputVariableName, entryInputVariable); - code.add("$N.add($N);", modifiableVariableName, entryOutputVariable) - .add("});") - .add("$N = $T.unmodifiableList($N);", outputVariableName, Collections.class, modifiableVariableName) + String entryOutputVariable = + copyMethodBody(code, builderTransform, variableSource, enumTransform, entryInputVariable, listEntryModel); + + code.add("$N.add($N);", modifiableVariableName, entryOutputVariable) + .add("});"); + } + code.add("$N = $T.unmodifiableList($N);", outputVariableName, Collections.class, modifiableVariableName) .add("}"); return outputVariableName; @@ -299,7 +308,8 @@ private String copyMethodBody(CodeBlock.Builder code, BuilderTransform builderTr .add("if ($1N == null || $1N instanceof $2T) {", inputVariableName, SdkAutoConstructMap.class) .add("$N = $T.getInstance();", outputVariableName, DefaultSdkAutoConstructMap.class) .add("} else {") - .add("$T $N = new $T<>();", outputMapType, modifiableVariableName, LinkedHashMap.class); + .add("$T $N = new $T<>($N.size());", + outputMapType, modifiableVariableName, LinkedHashMap.class, inputVariableName); String keyInputVariable = variableSource.getNew("key"); String valueInputVariable = variableSource.getNew("value"); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/blobmaptypecopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/blobmaptypecopier.java index 1d8d584c70e3..5564058f5b59 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/blobmaptypecopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/blobmaptypecopier.java @@ -17,7 +17,7 @@ static Map copy(Map blobMapTypeParam) { if (blobMapTypeParam == null || blobMapTypeParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(blobMapTypeParam.size()); blobMapTypeParam.forEach((key, value) -> { modifiableMap.put(key, value); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofblobstypecopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofblobstypecopier.java index 8e7460713c39..eb010928c014 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofblobstypecopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofblobstypecopier.java @@ -18,10 +18,7 @@ static List copy(Collection listOfBlobsTypeParam) { if (listOfBlobsTypeParam == null || listOfBlobsTypeParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); - listOfBlobsTypeParam.forEach(entry -> { - modifiableList.add(entry); - }); + List modifiableList = new ArrayList<>(listOfBlobsTypeParam); list = Collections.unmodifiableList(modifiableList); } return list; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofenumscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofenumscopier.java index cfc58e7348d6..973996a4202f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofenumscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofenumscopier.java @@ -17,7 +17,7 @@ static List copy(Collection listOfEnumsParam) { if (listOfEnumsParam == null || listOfEnumsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfEnumsParam.size()); listOfEnumsParam.forEach(entry -> { modifiableList.add(entry); }); @@ -31,7 +31,7 @@ static List copyEnumToString(Collection listOfEnumsParam) { if (listOfEnumsParam == null || listOfEnumsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfEnumsParam.size()); listOfEnumsParam.forEach(entry -> { String result = entry.toString(); modifiableList.add(result); @@ -46,7 +46,7 @@ static List copyStringToEnum(Collection listOfEnumsParam) { if (listOfEnumsParam == null || listOfEnumsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfEnumsParam.size()); listOfEnumsParam.forEach(entry -> { EnumType result = EnumType.fromValue(entry); modifiableList.add(result); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofintegerscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofintegerscopier.java index 85161b2db021..ee74fb09e017 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofintegerscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofintegerscopier.java @@ -17,10 +17,7 @@ static List copy(Collection listOfIntegersParam) { if (listOfIntegersParam == null || listOfIntegersParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); - listOfIntegersParam.forEach(entry -> { - modifiableList.add(entry); - }); + List modifiableList = new ArrayList<>(listOfIntegersParam); list = Collections.unmodifiableList(modifiableList); } return list; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistoflistofstringscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistoflistofstringscopier.java index 69d2076ba01b..6adcc8281f8d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistoflistofstringscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistoflistofstringscopier.java @@ -13,27 +13,24 @@ @Generated("software.amazon.awssdk:codegen") final class ListOfListOfListOfStringsCopier { static List>> copy( - Collection>> listOfListOfListOfStringsParam) { + Collection>> listOfListOfListOfStringsParam) { List>> list; if (listOfListOfListOfStringsParam == null || listOfListOfListOfStringsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List>> modifiableList = new ArrayList<>(); + List>> modifiableList = new ArrayList<>(listOfListOfListOfStringsParam.size()); listOfListOfListOfStringsParam.forEach(entry -> { List> list1; if (entry == null || entry instanceof SdkAutoConstructList) { list1 = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList1 = new ArrayList<>(); + List> modifiableList1 = new ArrayList<>(entry.size()); entry.forEach(entry1 -> { List list2; if (entry1 == null || entry1 instanceof SdkAutoConstructList) { list2 = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList2 = new ArrayList<>(); - entry1.forEach(entry2 -> { - modifiableList2.add(entry2); - }); + List modifiableList2 = new ArrayList<>(entry1); list2 = Collections.unmodifiableList(modifiableList2); } modifiableList1.add(list2); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistofstringscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistofstringscopier.java index c72b73af2a38..e48dd120bc2a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistofstringscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listoflistofstringscopier.java @@ -17,16 +17,13 @@ static List> copy(Collection> listOfLi if (listOfListOfStringsParam == null || listOfListOfStringsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfListOfStringsParam.size()); listOfListOfStringsParam.forEach(entry -> { List list1; if (entry == null || entry instanceof SdkAutoConstructList) { list1 = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList1 = new ArrayList<>(); - entry.forEach(entry1 -> { - modifiableList1.add(entry1); - }); + List modifiableList1 = new ArrayList<>(entry); list1 = Collections.unmodifiableList(modifiableList1); } modifiableList.add(list1); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofenumtostringcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofenumtostringcopier.java index 9de0c299c081..c2e6eed148fb 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofenumtostringcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofenumtostringcopier.java @@ -21,13 +21,13 @@ static List> copy(Collection> if (listOfMapOfEnumToStringParam == null || listOfMapOfEnumToStringParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfEnumToStringParam.size()); listOfMapOfEnumToStringParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -45,13 +45,13 @@ static List> copyEnumToString(Collection> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfEnumToStringParam.size()); listOfMapOfEnumToStringParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { String result = key.toString(); modifiableMap.put(result, value); @@ -70,13 +70,13 @@ static List> copyStringToEnum(Collection> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfEnumToStringParam.size()); listOfMapOfEnumToStringParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); if (result != EnumType.UNKNOWN_TO_SDK_VERSION) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofstringtostructcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofstringtostructcopier.java index 05e9c80325a9..f5336117a38a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofstringtostructcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofstringtostructcopier.java @@ -17,18 +17,18 @@ @Generated("software.amazon.awssdk:codegen") final class ListOfMapOfStringToStructCopier { static List> copy( - Collection> listOfMapOfStringToStructParam) { + Collection> listOfMapOfStringToStructParam) { List> list; if (listOfMapOfStringToStructParam == null || listOfMapOfStringToStructParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfStringToStructParam.size()); listOfMapOfStringToStructParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -42,18 +42,18 @@ static List> copy( } static List> copyFromBuilder( - Collection> listOfMapOfStringToStructParam) { + Collection> listOfMapOfStringToStructParam) { List> list; if (listOfMapOfStringToStructParam == null || listOfMapOfStringToStructParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfStringToStructParam.size()); listOfMapOfStringToStructParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { SimpleStruct member = value == null ? null : value.build(); modifiableMap.put(key, member); @@ -68,18 +68,18 @@ static List> copyFromBuilder( } static List> copyToBuilder( - Collection> listOfMapOfStringToStructParam) { + Collection> listOfMapOfStringToStructParam) { List> list; if (listOfMapOfStringToStructParam == null || listOfMapOfStringToStructParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapOfStringToStructParam.size()); listOfMapOfStringToStructParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { SimpleStruct.Builder member = value == null ? null : value.toBuilder(); modifiableMap.put(key, member); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapstringtostringcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapstringtostringcopier.java index a5001b779242..476c81792f33 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapstringtostringcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapstringtostringcopier.java @@ -21,13 +21,13 @@ static List> copy(Collection> if (listOfMapStringToStringParam == null || listOfMapStringToStringParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(listOfMapStringToStringParam.size()); listOfMapStringToStringParam.forEach(entry -> { Map map; if (entry == null || entry instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(entry.size()); entry.forEach((key, value) -> { modifiableMap.put(key, value); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofsimplestructscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofsimplestructscopier.java index aff15514e893..ca3bd2f0b292 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofsimplestructscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofsimplestructscopier.java @@ -17,7 +17,7 @@ static List copy(Collection listOfSimpleSt if (listOfSimpleStructsParam == null || listOfSimpleStructsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfSimpleStructsParam.size()); listOfSimpleStructsParam.forEach(entry -> { modifiableList.add(entry); }); @@ -31,7 +31,7 @@ static List copyFromBuilder(Collection modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfSimpleStructsParam.size()); listOfSimpleStructsParam.forEach(entry -> { SimpleStruct member = entry == null ? null : entry.build(); modifiableList.add(member); @@ -46,7 +46,7 @@ static List copyToBuilder(Collection modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(listOfSimpleStructsParam.size()); listOfSimpleStructsParam.forEach(entry -> { SimpleStruct.Builder member = entry == null ? null : entry.toBuilder(); modifiableList.add(member); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofstringscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofstringscopier.java index e387080391bf..3508a913da51 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofstringscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofstringscopier.java @@ -17,10 +17,7 @@ static List copy(Collection listOfStringsParam) { if (listOfStringsParam == null || listOfStringsParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); - listOfStringsParam.forEach(entry -> { - modifiableList.add(entry); - }); + List modifiableList = new ArrayList<>(listOfStringsParam); list = Collections.unmodifiableList(modifiableList); } return list; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtoenumcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtoenumcopier.java index 4557d0dadbe7..724a0e946705 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtoenumcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtoenumcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfEnumToEnumParam) { if (mapOfEnumToEnumParam == null || mapOfEnumToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToEnumParam.size()); mapOfEnumToEnumParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -30,7 +30,7 @@ static Map copyEnumToString(Map mapOfEnumToE if (mapOfEnumToEnumParam == null || mapOfEnumToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToEnumParam.size()); mapOfEnumToEnumParam.forEach((key, value) -> { String result = key.toString(); String result1 = value.toString(); @@ -46,7 +46,7 @@ static Map copyStringToEnum(Map mapOfEnumToE if (mapOfEnumToEnumParam == null || mapOfEnumToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToEnumParam.size()); mapOfEnumToEnumParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); EnumType result1 = EnumType.fromValue(value); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtolistofenumscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtolistofenumscopier.java index 8c38964d2257..ff0d8aa06a1c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtolistofenumscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtolistofenumscopier.java @@ -21,13 +21,13 @@ static Map> copy(Map> if (mapOfEnumToListOfEnumsParam == null || mapOfEnumToListOfEnumsParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToListOfEnumsParam.size()); mapOfEnumToListOfEnumsParam.forEach((key, value) -> { List list; if (value == null || value instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(value.size()); value.forEach(entry -> { modifiableList.add(entry); }); @@ -45,14 +45,14 @@ static Map> copyEnumToString(Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToListOfEnumsParam.size()); mapOfEnumToListOfEnumsParam.forEach((key, value) -> { String result = key.toString(); List list; if (value == null || value instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(value.size()); value.forEach(entry -> { String result1 = entry.toString(); modifiableList.add(result1); @@ -71,14 +71,14 @@ static Map> copyStringToEnum(Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToListOfEnumsParam.size()); mapOfEnumToListOfEnumsParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); List list; if (value == null || value instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(value.size()); value.forEach(entry -> { EnumType result1 = EnumType.fromValue(entry); modifiableList.add(result1); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtomapofstringtoenumcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtomapofstringtoenumcopier.java index 8b356484b87a..ccfaa58a6db6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtomapofstringtoenumcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtomapofstringtoenumcopier.java @@ -16,13 +16,13 @@ static Map> copy(Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToMapOfStringToEnumParam.size()); mapOfEnumToMapOfStringToEnumParam.forEach((key, value) -> { Map map1; if (value == null || value instanceof SdkAutoConstructMap) { map1 = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap1 = new LinkedHashMap<>(); + Map modifiableMap1 = new LinkedHashMap<>(value.size()); value.forEach((key1, value1) -> { modifiableMap1.put(key1, value1); }); @@ -36,19 +36,19 @@ static Map> copy(Map> copyEnumToString( - Map> mapOfEnumToMapOfStringToEnumParam) { + Map> mapOfEnumToMapOfStringToEnumParam) { Map> map; if (mapOfEnumToMapOfStringToEnumParam == null || mapOfEnumToMapOfStringToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToMapOfStringToEnumParam.size()); mapOfEnumToMapOfStringToEnumParam.forEach((key, value) -> { String result = key.toString(); Map map1; if (value == null || value instanceof SdkAutoConstructMap) { map1 = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap1 = new LinkedHashMap<>(); + Map modifiableMap1 = new LinkedHashMap<>(value.size()); value.forEach((key1, value1) -> { String result1 = value1.toString(); modifiableMap1.put(key1, result1); @@ -63,19 +63,19 @@ static Map> copyEnumToString( } static Map> copyStringToEnum( - Map> mapOfEnumToMapOfStringToEnumParam) { + Map> mapOfEnumToMapOfStringToEnumParam) { Map> map; if (mapOfEnumToMapOfStringToEnumParam == null || mapOfEnumToMapOfStringToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfEnumToMapOfStringToEnumParam.size()); mapOfEnumToMapOfStringToEnumParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); Map map1; if (value == null || value instanceof SdkAutoConstructMap) { map1 = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap1 = new LinkedHashMap<>(); + Map modifiableMap1 = new LinkedHashMap<>(value.size()); value.forEach((key1, value1) -> { EnumType result1 = EnumType.fromValue(value1); modifiableMap1.put(key1, result1); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtosimplestructcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtosimplestructcopier.java index 7347460f992b..92cfdfdc3b2e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtosimplestructcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtosimplestructcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfE if (mapOfEnumToSimpleStructParam == null || mapOfEnumToSimpleStructParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToSimpleStructParam.size()); mapOfEnumToSimpleStructParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -30,7 +30,7 @@ static Map copyFromBuilder(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToSimpleStructParam.size()); mapOfEnumToSimpleStructParam.forEach((key, value) -> { SimpleStruct member = value == null ? null : value.build(); modifiableMap.put(key, member); @@ -45,7 +45,7 @@ static Map copyToBuilder(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToSimpleStructParam.size()); mapOfEnumToSimpleStructParam.forEach((key, value) -> { SimpleStruct.Builder member = value == null ? null : value.toBuilder(); modifiableMap.put(key, member); @@ -60,7 +60,7 @@ static Map copyEnumToString(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToSimpleStructParam.size()); mapOfEnumToSimpleStructParam.forEach((key, value) -> { String result = key.toString(); modifiableMap.put(result, value); @@ -75,7 +75,7 @@ static Map copyStringToEnum(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToSimpleStructParam.size()); mapOfEnumToSimpleStructParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); if (result != EnumType.UNKNOWN_TO_SDK_VERSION) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtostringcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtostringcopier.java index bb103ed19e4e..ea6b32d062e6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtostringcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtostringcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfEnumToStringParam) { if (mapOfEnumToStringParam == null || mapOfEnumToStringParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToStringParam.size()); mapOfEnumToStringParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -30,7 +30,7 @@ static Map copyEnumToString(Map mapOfEnumToStr if (mapOfEnumToStringParam == null || mapOfEnumToStringParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToStringParam.size()); mapOfEnumToStringParam.forEach((key, value) -> { String result = key.toString(); modifiableMap.put(result, value); @@ -45,7 +45,7 @@ static Map copyStringToEnum(Map mapOfEnumToStr if (mapOfEnumToStringParam == null || mapOfEnumToStringParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfEnumToStringParam.size()); mapOfEnumToStringParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(key); if (result != EnumType.UNKNOWN_TO_SDK_VERSION) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtoenumcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtoenumcopier.java index d58aad27e4ae..3182110bb021 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtoenumcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtoenumcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfStringToEnumParam) { if (mapOfStringToEnumParam == null || mapOfStringToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToEnumParam.size()); mapOfStringToEnumParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -30,7 +30,7 @@ static Map copyEnumToString(Map mapOfStringToE if (mapOfStringToEnumParam == null || mapOfStringToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToEnumParam.size()); mapOfStringToEnumParam.forEach((key, value) -> { String result = value.toString(); modifiableMap.put(key, result); @@ -45,7 +45,7 @@ static Map copyStringToEnum(Map mapOfStringToE if (mapOfStringToEnumParam == null || mapOfStringToEnumParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToEnumParam.size()); mapOfStringToEnumParam.forEach((key, value) -> { EnumType result = EnumType.fromValue(value); modifiableMap.put(key, result); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtointegerlistcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtointegerlistcopier.java index 145a72261035..f62933fc273f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtointegerlistcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtointegerlistcopier.java @@ -21,16 +21,13 @@ static Map> copy(Map if (mapOfStringToIntegerListParam == null || mapOfStringToIntegerListParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map> modifiableMap = new LinkedHashMap<>(); + Map> modifiableMap = new LinkedHashMap<>(mapOfStringToIntegerListParam.size()); mapOfStringToIntegerListParam.forEach((key, value) -> { List list; if (value == null || value instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); - value.forEach(entry -> { - modifiableList.add(entry); - }); + List modifiableList = new ArrayList<>(value); list = Collections.unmodifiableList(modifiableList); } modifiableMap.put(key, list); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtolistoflistofstringscopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtolistoflistofstringscopier.java index 22be1de439e5..d72467203353 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtolistoflistofstringscopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtolistoflistofstringscopier.java @@ -17,27 +17,24 @@ @Generated("software.amazon.awssdk:codegen") final class MapOfStringToListOfListOfStringsCopier { static Map>> copy( - Map>> mapOfStringToListOfListOfStringsParam) { + Map>> mapOfStringToListOfListOfStringsParam) { Map>> map; if (mapOfStringToListOfListOfStringsParam == null || mapOfStringToListOfListOfStringsParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map>> modifiableMap = new LinkedHashMap<>(); + Map>> modifiableMap = new LinkedHashMap<>(mapOfStringToListOfListOfStringsParam.size()); mapOfStringToListOfListOfStringsParam.forEach((key, value) -> { List> list; if (value == null || value instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List> modifiableList = new ArrayList<>(); + List> modifiableList = new ArrayList<>(value.size()); value.forEach(entry -> { List list1; if (entry == null || entry instanceof SdkAutoConstructList) { list1 = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList1 = new ArrayList<>(); - entry.forEach(entry1 -> { - modifiableList1.add(entry1); - }); + List modifiableList1 = new ArrayList<>(entry); list1 = Collections.unmodifiableList(modifiableList1); } modifiableList.add(list1); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtosimplestructcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtosimplestructcopier.java index 058e180259b7..6a41c80d8e65 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtosimplestructcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtosimplestructcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfS if (mapOfStringToSimpleStructParam == null || mapOfStringToSimpleStructParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToSimpleStructParam.size()); mapOfStringToSimpleStructParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -30,7 +30,7 @@ static Map copyFromBuilder(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToSimpleStructParam.size()); mapOfStringToSimpleStructParam.forEach((key, value) -> { SimpleStruct member = value == null ? null : value.build(); modifiableMap.put(key, member); @@ -45,7 +45,7 @@ static Map copyToBuilder(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToSimpleStructParam.size()); mapOfStringToSimpleStructParam.forEach((key, value) -> { SimpleStruct.Builder member = value == null ? null : value.toBuilder(); modifiableMap.put(key, member); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtostringcopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtostringcopier.java index 122be42e195f..833117d18d9f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtostringcopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtostringcopier.java @@ -16,7 +16,7 @@ static Map copy(Map mapOfStringToStringParam) { if (mapOfStringToStringParam == null || mapOfStringToStringParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(mapOfStringToStringParam.size()); mapOfStringToStringParam.forEach((key, value) -> { modifiableMap.put(key, value); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivelisttypecopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivelisttypecopier.java index cab8c63d1f40..1ff5f4811798 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivelisttypecopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivelisttypecopier.java @@ -17,7 +17,7 @@ static List copy(Collection if (recursiveListTypeParam == null || recursiveListTypeParam instanceof SdkAutoConstructList) { list = DefaultSdkAutoConstructList.getInstance(); } else { - List modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(recursiveListTypeParam.size()); recursiveListTypeParam.forEach(entry -> { modifiableList.add(entry); }); @@ -31,7 +31,7 @@ static List copyFromBuilder(Collection modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(recursiveListTypeParam.size()); recursiveListTypeParam.forEach(entry -> { RecursiveStructType member = entry == null ? null : entry.build(); modifiableList.add(member); @@ -46,7 +46,7 @@ static List copyToBuilder(Collection modifiableList = new ArrayList<>(); + List modifiableList = new ArrayList<>(recursiveListTypeParam.size()); recursiveListTypeParam.forEach(entry -> { RecursiveStructType.Builder member = entry == null ? null : entry.toBuilder(); modifiableList.add(member); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivemaptypecopier.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivemaptypecopier.java index abac104e34b9..0a31f303d695 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivemaptypecopier.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivemaptypecopier.java @@ -16,7 +16,7 @@ static Map copy(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(recursiveMapTypeParam.size()); recursiveMapTypeParam.forEach((key, value) -> { modifiableMap.put(key, value); }); @@ -26,12 +26,12 @@ static Map copy(Map copyFromBuilder( - Map recursiveMapTypeParam) { + Map recursiveMapTypeParam) { Map map; if (recursiveMapTypeParam == null || recursiveMapTypeParam instanceof SdkAutoConstructMap) { map = DefaultSdkAutoConstructMap.getInstance(); } else { - Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(recursiveMapTypeParam.size()); recursiveMapTypeParam.forEach((key, value) -> { RecursiveStructType member = value == null ? null : value.build(); modifiableMap.put(key, member); @@ -46,7 +46,7 @@ static Map copyToBuilder(Map modifiableMap = new LinkedHashMap<>(); + Map modifiableMap = new LinkedHashMap<>(recursiveMapTypeParam.size()); recursiveMapTypeParam.forEach((key, value) -> { RecursiveStructType.Builder member = value == null ? null : value.toBuilder(); modifiableMap.put(key, member); From d2933eb84ca9f7ad300f0592fd34fdc5c21afc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Wed, 4 Sep 2024 15:16:04 -0700 Subject: [PATCH 13/14] Add the new Smithy RPCv2 package --- .brazil.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.brazil.json b/.brazil.json index b896a3b15b19..8392d2ecec10 100644 --- a/.brazil.json +++ b/.brazil.json @@ -14,6 +14,7 @@ "aws-json-protocol": { "packageName": "AwsJavaSdk-Core-AwsJsonProtocol" }, "aws-query-protocol": { "packageName": "AwsJavaSdk-Core-AwsQueryProtocol" }, "aws-xml-protocol": { "packageName": "AwsJavaSdk-Core-AwsXmlProtocol" }, + "smithy-rpcv2-protocol": { "packageName": "AwsJavaSdk-Core-SmithyRpcV2Protocol" }, "cloudwatch-metric-publisher": { "packageName": "AwsJavaSdk-MetricPublisher-CloudWatch" }, "codegen": { "packageName": "AwsJavaSdk-Codegen" }, "dynamodb-enhanced": { "packageName": "AwsJavaSdk-DynamoDb-Enhanced" }, From 7855c938aa63ab10fb6d8db30cad0a194a69dea3 Mon Sep 17 00:00:00 2001 From: Manuel Sugawara Date: Tue, 10 Sep 2024 09:22:56 -0700 Subject: [PATCH 14/14] Sugmanue/rpcv2 improve cbor performance 04 (#5564) * Improve lookup by marshalling type * Improve trait lookup using TraitType --- .../internal/marshall/HeaderMarshaller.java | 7 +- .../marshall/JsonProtocolMarshaller.java | 3 +- .../marshall/QueryParamMarshaller.java | 3 +- .../marshall/SimpleTypeJsonMarshaller.java | 6 +- .../unmarshall/HeaderUnmarshaller.java | 3 +- .../unmarshall/JsonProtocolUnmarshaller.java | 7 +- .../marshall/ListQueryMarshaller.java | 3 +- .../internal/marshall/MapQueryMarshaller.java | 3 +- .../unmarshall/ListQueryUnmarshaller.java | 3 +- .../unmarshall/MapQueryUnmarshaller.java | 3 +- .../unmarshall/QueryProtocolUnmarshaller.java | 7 +- .../internal/marshall/HeaderMarshaller.java | 5 +- .../marshall/QueryParamMarshaller.java | 7 +- .../marshall/XmlPayloadMarshaller.java | 17 +- .../marshall/XmlProtocolMarshaller.java | 3 +- .../unmarshall/XmlPayloadUnmarshaller.java | 5 +- .../unmarshall/XmlProtocolUnmarshaller.java | 5 +- .../unmarshall/XmlResponseParserUtils.java | 3 +- .../core/AbstractMarshallingRegistry.java | 145 ++++++++++++++---- .../protocols/core/InstantToString.java | 3 +- .../protocols/core/NumberToInstant.java | 3 +- .../protocols/core/StringToInstant.java | 3 +- .../software/amazon/awssdk/core/SdkField.java | 111 ++++++++++++-- .../core/protocol/MarshallingKnownType.java | 101 ++++++++++++ .../awssdk/core/protocol/MarshallingType.java | 12 +- ...ataTypeConversionFailureHandlingTrait.java | 4 + .../awssdk/core/traits/DefaultValueTrait.java | 5 + .../awssdk/core/traits/JsonValueTrait.java | 5 + .../amazon/awssdk/core/traits/ListTrait.java | 5 + .../awssdk/core/traits/LocationTrait.java | 5 + .../amazon/awssdk/core/traits/MapTrait.java | 5 + .../awssdk/core/traits/PayloadTrait.java | 5 + .../awssdk/core/traits/RequiredTrait.java | 5 + .../core/traits/TimestampFormatTrait.java | 5 + .../amazon/awssdk/core/traits/Trait.java | 8 + .../amazon/awssdk/core/traits/TraitType.java | 84 ++++++++++ .../awssdk/core/traits/XmlAttributeTrait.java | 5 + .../core/traits/XmlAttributesTrait.java | 5 + .../TransferManagerJsonUnmarshaller.java | 3 +- 39 files changed, 544 insertions(+), 76 deletions(-) create mode 100644 core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingKnownType.java create mode 100644 core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TraitType.java diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java index 110cdf36a11b..cd6a411f7911 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java @@ -27,6 +27,7 @@ import software.amazon.awssdk.core.traits.JsonValueTrait; import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.RequiredTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.ValueToStringConverter; import software.amazon.awssdk.utils.BinaryUtils; import software.amazon.awssdk.utils.StringUtils; @@ -35,7 +36,7 @@ public final class HeaderMarshaller { public static final JsonMarshaller STRING = new SimpleHeaderMarshaller<>( - (val, field) -> field.containsTrait(JsonValueTrait.class) ? + (val, field) -> field.containsTrait(JsonValueTrait.class, TraitType.JSON_VALUE_TRAIT) ? BinaryUtils.toBase64(val.getBytes(StandardCharsets.UTF_8)) : val); public static final JsonMarshaller INTEGER = new SimpleHeaderMarshaller<>(ValueToStringConverter.FROM_INTEGER); @@ -61,7 +62,7 @@ public final class HeaderMarshaller { if (isNullOrEmpty(list)) { return; } - SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class).memberFieldInfo(); + SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class, TraitType.LIST_TRAIT).memberFieldInfo(); for (Object listValue : list) { if (shouldSkipElement(listValue)) { continue; @@ -72,7 +73,7 @@ public final class HeaderMarshaller { }; public static final JsonMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", paramName)); } }; diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java index 924803d47297..04ef0c286eca 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java @@ -36,6 +36,7 @@ import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.protocols.core.InstantToString; import software.amazon.awssdk.protocols.core.OperationInfo; @@ -227,7 +228,7 @@ private boolean isExplicitStringPayload(SdkField field) { } private boolean isExplicitPayloadMember(SdkField field) { - return field.containsTrait(PayloadTrait.class); + return field.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT); } private void marshallExplicitJsonPayload(SdkField field, Object val) { diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java index e6445670ab2a..fa511b0574bc 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/QueryParamMarshaller.java @@ -23,6 +23,7 @@ import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.RequiredTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.ValueToStringConverter; @SdkInternalApi @@ -65,7 +66,7 @@ public final class QueryParamMarshaller { }; public static final JsonMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", paramName)); } }; diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java index c4c5da8a74e1..9b59a6b05c7b 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.RequiredTrait; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.core.util.SdkAutoConstructList; import software.amazon.awssdk.core.util.SdkAutoConstructMap; import software.amazon.awssdk.protocols.json.StructuredJsonGenerator; @@ -39,7 +40,7 @@ public final class SimpleTypeJsonMarshaller { public static final JsonMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", Optional.ofNullable(paramName) .orElseGet(() -> "paramName null"))); @@ -122,7 +123,8 @@ public void marshall(Boolean val, StructuredJsonGenerator jsonGenerator, JsonMar if (paramName != null) { jsonGenerator.writeFieldName(paramName); } - TimestampFormatTrait trait = sdkField != null ? sdkField.getTrait(TimestampFormatTrait.class) : null; + TimestampFormatTrait trait = sdkField != null ? sdkField.getTrait(TimestampFormatTrait.class, + TraitType.TIMESTAMP_FORMAT_TRAIT) : null; if (trait != null) { switch (trait.format()) { case UNIX_TIMESTAMP: diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/HeaderUnmarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/HeaderUnmarshaller.java index 8f8cca4a4dcc..6c521c304e6a 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/HeaderUnmarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/HeaderUnmarshaller.java @@ -21,6 +21,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.traits.JsonValueTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.StringToValueConverter; import software.amazon.awssdk.protocols.jsoncore.JsonNode; import software.amazon.awssdk.utils.BinaryUtils; @@ -59,7 +60,7 @@ private HeaderUnmarshaller() { */ private static String unmarshallStringHeader(String value, SdkField field) { - return field.containsTrait(JsonValueTrait.class) ? + return field.containsTrait(JsonValueTrait.class, TraitType.JSON_VALUE_TRAIT) ? new String(BinaryUtils.fromBase64(value), StandardCharsets.UTF_8) : value; } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java index b4121852f332..f0732015aabb 100644 --- a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java +++ b/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonProtocolUnmarshaller.java @@ -38,6 +38,7 @@ import software.amazon.awssdk.core.traits.MapTrait; import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.core.StringToInstant; @@ -179,7 +180,7 @@ private static Document getDocumentFromJsonContent(JsonNode jsonContent) { return null; } - SdkField valueInfo = field.getTrait(MapTrait.class).valueFieldInfo(); + SdkField valueInfo = field.getTrait(MapTrait.class, TraitType.MAP_TRAIT).valueFieldInfo(); JsonUnmarshaller unmarshaller = context.getUnmarshaller(valueInfo.location(), valueInfo.marshallingType()); Map asObject = jsonContent.asObject(); Map map = new HashMap<>(asObject.size()); @@ -194,7 +195,7 @@ private static List unmarshallList(JsonUnmarshallerContext context, JsonNode return null; } - SdkField memberInfo = field.getTrait(ListTrait.class).memberFieldInfo(); + SdkField memberInfo = field.getTrait(ListTrait.class, TraitType.LIST_TRAIT).memberFieldInfo(); List asArray = jsonContent.asArray(); List result = new ArrayList<>(asArray.size()); for (JsonNode node : asArray) { @@ -249,7 +250,7 @@ private boolean isExplicitStringPayloadMember(SdkField f) { } private static boolean isExplicitPayloadMember(SdkField f) { - return f.containsTrait(PayloadTrait.class); + return f.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT); } private boolean isPayloadMemberOnUnmarshall(SdkField f) { diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java index 59f6c5b93f34..971dbb96f953 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java @@ -19,6 +19,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.traits.ListTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.core.util.SdkAutoConstructList; /** @@ -52,7 +53,7 @@ public void marshall(QueryMarshallerContext context, String path, List val, S return; } for (int i = 0; i < val.size(); i++) { - ListTrait listTrait = sdkField.getTrait(ListTrait.class); + ListTrait listTrait = sdkField.getTrait(ListTrait.class, TraitType.LIST_TRAIT); String listPath = pathResolver.resolve(path, i, listTrait); QueryMarshaller marshaller = context.marshallerRegistry().getMarshaller( ((SdkField) listTrait.memberFieldInfo()).marshallingType(), val); diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java index 81951313ed87..195125e027c6 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java @@ -20,13 +20,14 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.traits.MapTrait; +import software.amazon.awssdk.core.traits.TraitType; @SdkInternalApi public class MapQueryMarshaller implements QueryMarshaller> { @Override public void marshall(QueryMarshallerContext context, String path, Map val, SdkField> sdkField) { - MapTrait mapTrait = sdkField.getTrait(MapTrait.class); + MapTrait mapTrait = sdkField.getTrait(MapTrait.class, TraitType.MAP_TRAIT); AtomicInteger entryNum = new AtomicInteger(1); val.forEach((key, value) -> { diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/ListQueryUnmarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/ListQueryUnmarshaller.java index fdbaf536b063..aadac57e87b7 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/ListQueryUnmarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/ListQueryUnmarshaller.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.traits.ListTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.query.unmarshall.XmlElement; @SdkInternalApi @@ -29,7 +30,7 @@ public final class ListQueryUnmarshaller implements QueryUnmarshaller> { @Override public List unmarshall(QueryUnmarshallerContext context, List content, SdkField> field) { - ListTrait listTrait = field.getTrait(ListTrait.class); + ListTrait listTrait = field.getTrait(ListTrait.class, TraitType.LIST_TRAIT); List list = new ArrayList<>(); getMembers(content, listTrait).forEach(member -> { QueryUnmarshaller unmarshaller = context.getUnmarshaller(listTrait.memberFieldInfo().location(), diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/MapQueryUnmarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/MapQueryUnmarshaller.java index 9f7b36e276d6..55ae3a83d8e3 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/MapQueryUnmarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/MapQueryUnmarshaller.java @@ -23,6 +23,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.traits.MapTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.query.unmarshall.XmlElement; @SdkInternalApi @@ -31,7 +32,7 @@ public final class MapQueryUnmarshaller implements QueryUnmarshaller unmarshall(QueryUnmarshallerContext context, List content, SdkField> field) { Map map = new HashMap<>(); - MapTrait mapTrait = field.getTrait(MapTrait.class); + MapTrait mapTrait = field.getTrait(MapTrait.class, TraitType.MAP_TRAIT); SdkField mapValueSdkField = mapTrait.valueFieldInfo(); getEntries(content, mapTrait).forEach(entry -> { diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/QueryProtocolUnmarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/QueryProtocolUnmarshaller.java index b781ff9ac7c5..2940ea5063a6 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/QueryProtocolUnmarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/QueryProtocolUnmarshaller.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.PayloadTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.core.StringToInstant; import software.amazon.awssdk.protocols.core.StringToValueConverter; @@ -90,7 +91,7 @@ public Pair> unmarshall(SdkPo private boolean responsePayloadIsBlob(SdkPojo sdkPojo) { return sdkPojo.sdkFields().stream() .anyMatch(field -> field.marshallingType() == MarshallingType.SDK_BYTES && - field.containsTrait(PayloadTrait.class)); + field.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT)); } /** @@ -128,7 +129,9 @@ private String metadataKeyName(XmlElement c) { private SdkPojo unmarshall(QueryUnmarshallerContext context, SdkPojo sdkPojo, XmlElement root) { if (root != null) { for (SdkField field : sdkPojo.sdkFields()) { - if (field.containsTrait(PayloadTrait.class) && field.marshallingType() == MarshallingType.SDK_BYTES) { + if (field.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT) + && field.marshallingType() == MarshallingType.SDK_BYTES + ) { field.set(sdkPojo, SdkBytes.fromUtf8String(root.textContent())); } diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/HeaderMarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/HeaderMarshaller.java index 01ae907adfa0..b7b5c40b8f91 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/HeaderMarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/HeaderMarshaller.java @@ -26,6 +26,7 @@ import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.RequiredTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.ValueToStringConverter; import software.amazon.awssdk.utils.StringUtils; @@ -79,7 +80,7 @@ public void marshall(List list, XmlMarshallerContext context, String paramNam if (!shouldEmit(list)) { return; } - SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class).memberFieldInfo(); + SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class, TraitType.LIST_TRAIT).memberFieldInfo(); for (Object listValue : list) { if (shouldSkipElement(listValue)) { continue; @@ -102,7 +103,7 @@ protected boolean shouldEmit(List list) { }; public static final XmlMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", paramName)); } }; diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/QueryParamMarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/QueryParamMarshaller.java index 0cd24401a180..e2587a52d9ae 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/QueryParamMarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/QueryParamMarshaller.java @@ -25,6 +25,7 @@ import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.MapTrait; import software.amazon.awssdk.core.traits.RequiredTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.ValueToStringConverter; @SdkInternalApi @@ -62,11 +63,11 @@ public final class QueryParamMarshaller { return; } - MapTrait mapTrait = sdkField.getRequiredTrait(MapTrait.class); + MapTrait mapTrait = sdkField.getRequiredTrait(MapTrait.class, TraitType.MAP_TRAIT); SdkField valueField = mapTrait.valueFieldInfo(); for (Map.Entry entry : map.entrySet()) { - if (valueField.containsTrait(ListTrait.class)) { + if (valueField.containsTrait(ListTrait.class, TraitType.LIST_TRAIT)) { ((List) entry.getValue()).forEach(val -> { context.marshallerRegistry().getMarshaller(MarshallLocation.QUERY_PARAM, val) .marshall(val, context, entry.getKey(), null); @@ -81,7 +82,7 @@ public final class QueryParamMarshaller { }; public static final XmlMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", paramName)); } }; diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlPayloadMarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlPayloadMarshaller.java index af18aade55e1..b85f7c5cd7b3 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlPayloadMarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlPayloadMarshaller.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.MapTrait; import software.amazon.awssdk.core.traits.RequiredTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.core.traits.XmlAttributeTrait; import software.amazon.awssdk.core.traits.XmlAttributesTrait; import software.amazon.awssdk.core.util.SdkAutoConstructList; @@ -83,7 +84,7 @@ public void marshall(List val, XmlMarshallerContext context, String paramName @Override public void marshall(List list, XmlMarshallerContext context, String paramName, SdkField> sdkField, ValueToStringConverter.ValueToString> converter) { - ListTrait listTrait = sdkField.getRequiredTrait(ListTrait.class); + ListTrait listTrait = sdkField.getRequiredTrait(ListTrait.class, TraitType.LIST_TRAIT); if (!listTrait.isFlattened()) { context.xmlGenerator().startElement(paramName); @@ -125,7 +126,7 @@ protected boolean shouldEmit(List list, String paramName) { public void marshall(Map map, XmlMarshallerContext context, String paramName, SdkField> sdkField, ValueToStringConverter.ValueToString> converter) { - MapTrait mapTrait = sdkField.getRequiredTrait(MapTrait.class); + MapTrait mapTrait = sdkField.getRequiredTrait(MapTrait.class, TraitType.MAP_TRAIT); for (Map.Entry entry : map.entrySet()) { context.xmlGenerator().startElement("entry"); @@ -144,7 +145,7 @@ protected boolean shouldEmit(Map map, String paramName) { }; public static final XmlMarshaller NULL = (val, context, paramName, sdkField) -> { - if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class)) { + if (Objects.nonNull(sdkField) && sdkField.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) { throw new IllegalArgumentException(String.format("Parameter '%s' must not be null", paramName)); } }; @@ -180,8 +181,11 @@ public void marshall(T val, XmlMarshallerContext context, String paramName, SdkF return; } - if (sdkField != null && sdkField.getOptionalTrait(XmlAttributesTrait.class).isPresent()) { - XmlAttributesTrait attributeTrait = sdkField.getTrait(XmlAttributesTrait.class); + boolean hasXmlAttributesTrait = sdkField != null && + sdkField.getOptionalTrait(XmlAttributesTrait.class, + TraitType.XML_ATTRIBUTES_TRAIT).isPresent(); + if (hasXmlAttributesTrait) { + XmlAttributesTrait attributeTrait = sdkField.getTrait(XmlAttributesTrait.class, TraitType.XML_ATTRIBUTES_TRAIT); Map attributes = attributeTrait.attributes() .entrySet() .stream() @@ -209,7 +213,8 @@ protected boolean shouldEmit(T val, String paramName) { } private boolean isXmlAttribute(SdkField sdkField) { - return sdkField != null && sdkField.getOptionalTrait(XmlAttributeTrait.class).isPresent(); + return sdkField != null && sdkField.getOptionalTrait(XmlAttributeTrait.class, + TraitType.XML_ATTRIBUTE_TRAIT).isPresent(); } } diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlProtocolMarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlProtocolMarshaller.java index 2f6f6bb89eb7..c71ef1bccbd7 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlProtocolMarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/XmlProtocolMarshaller.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.protocols.core.InstantToString; import software.amazon.awssdk.protocols.core.OperationInfo; @@ -129,7 +130,7 @@ private boolean isBinary(SdkField field, Object val) { } private boolean isExplicitPayloadMember(SdkField field) { - return field.containsTrait(PayloadTrait.class); + return field.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT); } private boolean hasPayloadMembers(SdkPojo sdkPojo) { diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlPayloadUnmarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlPayloadUnmarshaller.java index b9f695092d9f..0ad6632d235a 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlPayloadUnmarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlPayloadUnmarshaller.java @@ -29,6 +29,7 @@ import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.MapTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.StringToValueConverter; import software.amazon.awssdk.protocols.query.unmarshall.XmlElement; @@ -57,7 +58,7 @@ public static SdkPojo unmarshallSdkPojo(XmlUnmarshallerContext context, List unmarshallList(XmlUnmarshallerContext context, List content, SdkField> field) { - ListTrait listTrait = field.getTrait(ListTrait.class); + ListTrait listTrait = field.getTrait(ListTrait.class, TraitType.LIST_TRAIT); List list = new ArrayList<>(); getMembers(content, listTrait).forEach(member -> { @@ -80,7 +81,7 @@ private static List getMembers(List content, ListTrait l public static Map unmarshallMap(XmlUnmarshallerContext context, List content, SdkField> field) { Map map = new HashMap<>(); - MapTrait mapTrait = field.getTrait(MapTrait.class); + MapTrait mapTrait = field.getTrait(MapTrait.class, TraitType.MAP_TRAIT); SdkField mapValueSdkField = mapTrait.valueFieldInfo(); getEntries(content, mapTrait).forEach(entry -> { diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlProtocolUnmarshaller.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlProtocolUnmarshaller.java index 56d950f917eb..d865e9383643 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlProtocolUnmarshaller.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlProtocolUnmarshaller.java @@ -32,6 +32,7 @@ import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.core.traits.XmlAttributeTrait; import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.core.StringToInstant; @@ -168,11 +169,11 @@ private boolean hasS3XmlEnvelopePrefix(String payload) { } private boolean isAttribute(SdkField field) { - return field.containsTrait(XmlAttributeTrait.class); + return field.containsTrait(XmlAttributeTrait.class, TraitType.XML_ATTRIBUTE_TRAIT); } private boolean isExplicitPayloadMember(SdkField field) { - return field.containsTrait(PayloadTrait.class); + return field.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT); } private boolean hasXmlPayload(SdkPojo sdkPojo, SdkHttpFullResponse response) { diff --git a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlResponseParserUtils.java b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlResponseParserUtils.java index c5d8088ec8cb..5804ad48a571 100644 --- a/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlResponseParserUtils.java +++ b/core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/unmarshall/XmlResponseParserUtils.java @@ -24,6 +24,7 @@ import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.protocol.MarshallingType; import software.amazon.awssdk.core.traits.PayloadTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.query.unmarshall.XmlDomParser; @@ -84,7 +85,7 @@ public static Optional> getBlobTypePayloadMemberToUnmarshal(SdkPojo } private static boolean isExplicitPayloadMember(SdkField f) { - return f.containsTrait(PayloadTrait.class); + return f.containsTrait(PayloadTrait.class, TraitType.PAYLOAD_TRAIT); } private static boolean hasPayloadMembers(SdkPojo sdkPojo) { diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java index e7fe57a7e856..afa8aaaf880c 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/AbstractMarshallingRegistry.java @@ -24,6 +24,7 @@ import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingKnownType; import software.amazon.awssdk.core.protocol.MarshallingType; /** @@ -31,16 +32,14 @@ */ @SdkProtectedApi public abstract class AbstractMarshallingRegistry { - - private final Map> registry; + private final MarshallingLocationRegistry locationRegistry; private final Set> marshallingTypes; private final Map, MarshallingType> marshallingTypeCache; protected AbstractMarshallingRegistry(Builder builder) { - this.registry = builder.registry; + this.locationRegistry = builder.locationRegistry.build(); this.marshallingTypes = builder.marshallingTypes; this.marshallingTypeCache = new HashMap<>(marshallingTypes.size()); - } /** @@ -52,17 +51,7 @@ protected AbstractMarshallingRegistry(Builder builder) { * @throws SdkClientException if no marshaller/unmarshaller is registered for the given location and type. */ protected Object get(MarshallLocation marshallLocation, MarshallingType marshallingType) { - Map byLocation = registry.get(marshallLocation); - if (byLocation == null) { - throw SdkClientException.create("No marshaller/unmarshaller registered for location " + marshallLocation.name()); - } - Object registered = byLocation.get(marshallingType); - if (registered == null) { - throw SdkClientException.create(String.format("No marshaller/unmarshaller of type %s registered for location %s.", - marshallingType, - marshallLocation.name())); - } - return registered; + return locationRegistry.get(marshallLocation, marshallingType); } @SuppressWarnings("unchecked") @@ -98,15 +87,15 @@ private MarshallingType populateMarshallingTypeCache(Class clzz) { * Builder for a {@link AbstractMarshallingRegistry}. */ public abstract static class Builder { - - private final Map> registry = new EnumMap<>(MarshallLocation.class); + private final MarshallingLocationRegistry.Builder locationRegistry; private final Set> marshallingTypes = new HashSet<>(); protected Builder() { + this.locationRegistry = MarshallingLocationRegistry.builder(); } protected Builder(AbstractMarshallingRegistry marshallingRegistry) { - deepCopy(this.registry, marshallingRegistry.registry); + this.locationRegistry = marshallingRegistry.locationRegistry.toBuilder(); this.marshallingTypes.addAll(marshallingRegistry.marshallingTypes); } @@ -114,21 +103,123 @@ protected Builder register(MarshallLocation marshallLocation, MarshallingType marshallingType, Object marshaller) { marshallingTypes.add(marshallingType); - registry.computeIfAbsent(marshallLocation, k -> new HashMap<>()); - registry.get(marshallLocation).put(marshallingType, marshaller); + locationRegistry.register(marshallLocation, marshallingType, marshaller); return this; } } /** - * Copies the map values from source to target making sure to create a new copy that can be owned by the source. + * A registry of marshaller per marshalling location and marshalling type. + */ + static class MarshallingLocationRegistry { + private final Map registry; + + private MarshallingLocationRegistry(Builder builder) { + this.registry = new EnumMap<>(MarshallLocation.class); + builder.registry.forEach((k, v) -> this.registry.put(k, v.build())); + } + + public Object get(MarshallLocation location, MarshallingType marshallingType) { + MarshallingTypeRegistry byLocation = registry.get(location); + if (byLocation != null) { + return byLocation.get(marshallingType); + } + return null; + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder(this); + } + + static class Builder { + private Map registry = new EnumMap<>(MarshallLocation.class); + + private Builder() { + } + + private Builder(MarshallingLocationRegistry marshallingLocationRegistry) { + marshallingLocationRegistry.registry.forEach((k, v) -> this.registry.put(k, v.toBuilder())); + } + + public Builder register( + MarshallLocation location, + MarshallingType marshallingType, + Object marshaller + ) { + registry.computeIfAbsent(location, x -> MarshallingTypeRegistry.builder()) + .register(marshallingType, marshaller); + return this; + } + + public MarshallingLocationRegistry build() { + return new MarshallingLocationRegistry(this); + } + } + } + + /** + * A registry of marshaller per marshalling type. It keeps two maps, the level 1 is faster as it uses + * an {@link EnumMap} for the known marshalling types. The level 2 one is slower, but it can be used + * for other, not known marshalling types. */ - private static void deepCopy( - Map> target, - Map> source - ) { - for (Map.Entry> sourceKvp : source.entrySet()) { - target.computeIfAbsent(sourceKvp.getKey(), (x) -> new HashMap<>()).putAll(sourceKvp.getValue()); + static class MarshallingTypeRegistry { + private final Map l1registry; + private final Map, Object> l2registry; + + private MarshallingTypeRegistry(Builder builder) { + this.l1registry = new EnumMap<>(builder.l1registry); + this.l2registry = builder.l2registry; + } + + + public Object get(MarshallingType marshallingType) { + MarshallingKnownType knownType = marshallingType.getKnownType(); + if (knownType != null) { + return l1registry.get(knownType); + } + return l2registry.get(marshallingType); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder(this); + } + + static class Builder { + private Map l1registry = new EnumMap<>(MarshallingKnownType.class); + private Map, Object> l2registry = new HashMap<>(); + + private Builder() { + } + + private Builder(MarshallingTypeRegistry marshallingTypeRegistry) { + this.l1registry.putAll(marshallingTypeRegistry.l1registry); + this.l2registry.putAll(marshallingTypeRegistry.l2registry); + } + + public Builder register( + MarshallingType marshallingType, + Object marshaller + ) { + MarshallingKnownType knownType = marshallingType.getKnownType(); + if (knownType != null) { + l1registry.put(knownType, marshaller); + } else { + l2registry.put(marshallingType, marshaller); + } + return this; + } + + public MarshallingTypeRegistry build() { + return new MarshallingTypeRegistry(this); + } } } } diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/InstantToString.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/InstantToString.java index 96a0878a894d..251bf50441b4 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/InstantToString.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/InstantToString.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.core.ValueToStringConverter.ValueToString; import software.amazon.awssdk.utils.DateUtils; @@ -44,7 +45,7 @@ public String convert(Instant val, SdkField sdkField) { return null; } TimestampFormatTrait.Format format = - sdkField.getOptionalTrait(TimestampFormatTrait.class) + sdkField.getOptionalTrait(TimestampFormatTrait.class, TraitType.TIMESTAMP_FORMAT_TRAIT) .map(TimestampFormatTrait::format) .orElseGet(() -> getDefaultTimestampFormat(sdkField.location(), defaultFormats)); switch (format) { diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java index 4c91db234bb5..bce761ac5181 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/NumberToInstant.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; /** * Converts a number value to an {@link Instant} type. Respects the {@link TimestampFormatTrait} if present. @@ -59,7 +60,7 @@ public Instant convert(Number value, SdkField field) { } private TimestampFormatTrait.Format resolveTimestampFormat(SdkField field) { - TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class); + TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class, TraitType.TIMESTAMP_FORMAT_TRAIT); if (trait == null) { TimestampFormatTrait.Format format = defaultFormats.get(field.location()); if (format == null) { diff --git a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java index 8d44e4adf104..5039b872dc14 100644 --- a/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java +++ b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java @@ -23,6 +23,7 @@ import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.traits.TimestampFormatTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.utils.DateUtils; /** @@ -80,7 +81,7 @@ private Function safeParseDate(Function dateUn } private TimestampFormatTrait.Format resolveTimestampFormat(SdkField field) { - TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class); + TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class, TraitType.TIMESTAMP_FORMAT_TRAIT); if (trait == null) { TimestampFormatTrait.Format format = defaultFormats.get(field.location()); if (format == null) { diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkField.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkField.java index 063ef85f2cd6..98561baca4ac 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkField.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkField.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.core; import java.util.Arrays; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -29,6 +30,7 @@ import software.amazon.awssdk.core.traits.DefaultValueTrait; import software.amazon.awssdk.core.traits.LocationTrait; import software.amazon.awssdk.core.traits.Trait; +import software.amazon.awssdk.core.traits.TraitType; /** * Metadata about a member in an {@link SdkPojo}. Contains information about how to marshall/unmarshall. @@ -45,23 +47,55 @@ public final class SdkField { private final Supplier constructor; private final BiConsumer setter; private final Function getter; - private final Map, Trait> traits; + private final Map l1Traits; + private final Map, Trait> l2Traits; private SdkField(Builder builder) { this.memberName = builder.memberName; this.marshallingType = builder.marshallingType; - this.traits = new HashMap<>(builder.traits); + this.l1Traits = createL1Traits(builder.traits); + this.l2Traits = createL2Traits(builder.traits); this.constructor = builder.constructor; this.setter = builder.setter; this.getter = builder.getter; // Eagerly dereference location trait since it's so commonly used. - LocationTrait locationTrait = getTrait(LocationTrait.class); + LocationTrait locationTrait = getTrait(LocationTrait.class, TraitType.LOCATION_TRAIT); this.location = locationTrait.location(); this.locationName = locationTrait.locationName(); this.unmarshallLocationName = locationTrait.unmarshallLocationName(); } + /** + * Creates an L1 traits map. This map is for fast lookup of known traits. + */ + private static Map createL1Traits(Map, Trait> traits) { + Map result = new EnumMap<>(TraitType.class); + for (Map.Entry, Trait> kvp : traits.entrySet()) { + Trait trait = kvp.getValue(); + TraitType type = trait.type(); + if (type != null) { + result.put(type, trait); + } + } + return result; + } + + /** + * Creates an L2 traits map. This map is for regular lookup of unknown traits. + */ + private static Map, Trait> createL2Traits(Map, Trait> traits) { + Map, Trait> result = new HashMap<>(); + for (Map.Entry, Trait> kvp : traits.entrySet()) { + Trait trait = kvp.getValue(); + TraitType type = trait.type(); + if (type == null) { + result.put(kvp.getKey(), trait); + } + } + return result; + } + public String memberName() { return memberName; } @@ -92,7 +126,7 @@ public String locationName() { */ public boolean ignoreDataTypeConversionFailures() { DataTypeConversionFailureHandlingTrait dataTypeConversionFailureHandlingTrait = - getTrait(DataTypeConversionFailureHandlingTrait.class); + getTrait(DataTypeConversionFailureHandlingTrait.class, TraitType.DATA_TYPE_CONVERSION_FAILURE_HANDLING_TRAIT); return dataTypeConversionFailureHandlingTrait != null; } @@ -118,7 +152,24 @@ public Supplier constructor() { */ @SuppressWarnings("unchecked") public T getTrait(Class clzz) { - return (T) traits.get(clzz); + TraitType type = TraitType.from(clzz); + if (type != null) { + return (T) l1Traits.get(type); + } + return (T) l2Traits.get(clzz); + } + + /** + * Gets the trait of the specified class and known type if available. + * + * @param clzz Trait class to get. + * @param type The {@link TraitType} for this trait. + * @param Type of trait. + * @return Trait instance or null if trait is not present. + */ + @SuppressWarnings("unchecked") + public T getTrait(Class clzz, TraitType type) { + return (T) l1Traits.get(type); } /** @@ -130,7 +181,20 @@ public T getTrait(Class clzz) { */ @SuppressWarnings("unchecked") public Optional getOptionalTrait(Class clzz) { - return Optional.ofNullable((T) traits.get(clzz)); + return Optional.ofNullable((T) getTrait(clzz)); + } + + /** + * Gets the trait of the specified class if available. + * + * @param clzz Trait class to get. + * @param Type of trait. + * @param type The {@link TraitType} for this trait. + * @return Optional of trait instance. + */ + @SuppressWarnings("unchecked") + public Optional getOptionalTrait(Class clzz, TraitType type) { + return Optional.ofNullable((T) getTrait(clzz, type)); } /** @@ -143,7 +207,25 @@ public Optional getOptionalTrait(Class clzz) { */ @SuppressWarnings("unchecked") public T getRequiredTrait(Class clzz) throws IllegalStateException { - T trait = (T) traits.get(clzz); + T trait = (T) getTrait(clzz); + if (trait == null) { + throw new IllegalStateException(memberName + " member is missing " + clzz.getSimpleName()); + } + return trait; + } + + /** + * Gets the trait of the specified class, or throw {@link IllegalStateException} if not available. + * + * @param clzz Trait class to get. + * @param Type of trait. + * @param type The {@link TraitType} for this trait. + * @return Trait instance. + * @throws IllegalStateException if trait is not present. + */ + @SuppressWarnings("unchecked") + public T getRequiredTrait(Class clzz, TraitType type) throws IllegalStateException { + T trait = (T) getTrait(clzz, type); if (trait == null) { throw new IllegalStateException(memberName + " member is missing " + clzz.getSimpleName()); } @@ -157,7 +239,18 @@ public T getRequiredTrait(Class clzz) throws IllegalStateEx * @return True if trait is present, false if not. */ public boolean containsTrait(Class clzz) { - return traits.containsKey(clzz); + return getTrait(clzz) != null; + } + + /** + * Checks if a given {@link Trait} is present on the field. + * + * @param clzz Trait class to check. + * @param type The {@link TraitType} for this trait. + * @return True if trait is present, false if not. + */ + public boolean containsTrait(Class clzz, TraitType type) { + return getTrait(clzz, type) != null; } /** @@ -180,7 +273,7 @@ private TypeT get(Object pojo) { */ public TypeT getValueOrDefault(Object pojo) { TypeT val = this.get(pojo); - DefaultValueTrait trait = getTrait(DefaultValueTrait.class); + DefaultValueTrait trait = getTrait(DefaultValueTrait.class, TraitType.DEFAULT_VALUE_TRAIT); return (trait == null ? val : (TypeT) trait.resolveValue(val)); } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingKnownType.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingKnownType.java new file mode 100644 index 000000000000..255f4313c00c --- /dev/null +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingKnownType.java @@ -0,0 +1,101 @@ +/* + * 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.core.protocol; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.core.SdkPojo; +import software.amazon.awssdk.core.document.Document; + +/** + * Enum of known types of marshalling types. This enum is used to use EnumMap's for fast lookup of traits. + */ +@SdkProtectedApi +public enum MarshallingKnownType { + NULL, + STRING, + INTEGER, + LONG, + FLOAT, + DOUBLE, + BIG_DECIMAL, + BOOLEAN, + INSTANT, + SDK_BYTES, + SDK_POJO, + LIST, + MAP, + SHORT, + BYTE, + DOCUMENT, + ; + + public static MarshallingKnownType from(Class clazz) { + if (clazz == Void.class) { + return NULL; + } + if (clazz == String.class) { + return STRING; + } + if (clazz == Integer.class) { + return INTEGER; + } + if (clazz == Long.class) { + return LONG; + } + if (clazz == Float.class) { + return FLOAT; + } + if (clazz == Double.class) { + return DOUBLE; + } + if (clazz == BigDecimal.class) { + return BIG_DECIMAL; + } + if (clazz == Boolean.class) { + return BOOLEAN; + } + if (clazz == Instant.class) { + return INSTANT; + } + if (clazz == SdkBytes.class) { + return SDK_BYTES; + } + if (clazz == SdkPojo.class) { + return SDK_POJO; + } + if (clazz == List.class) { + return LIST; + } + if (clazz == Map.class) { + return MAP; + } + if (clazz == Short.class) { + return SHORT; + } + if (clazz == Byte.class) { + return BYTE; + } + if (clazz == Document.class) { + return DOCUMENT; + } + return null; + } +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java index ee345d6e8619..b19c15af2479 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/MarshallingType.java @@ -69,20 +69,28 @@ public interface MarshallingType { Class getTargetClass(); + default MarshallingKnownType getKnownType() { + return null; + } + static MarshallingType newType(Class clzz) { return new MarshallingType() { + private final MarshallingKnownType knownType = MarshallingKnownType.from(clzz); @Override public Class getTargetClass() { return clzz; } + @Override + public MarshallingKnownType getKnownType() { + return knownType; + } + @Override public String toString() { return clzz.getSimpleName(); } }; - } - } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DataTypeConversionFailureHandlingTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DataTypeConversionFailureHandlingTrait.java index 243ff2dac30b..3323a1d8c956 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DataTypeConversionFailureHandlingTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DataTypeConversionFailureHandlingTrait.java @@ -19,4 +19,8 @@ @SdkProtectedApi public class DataTypeConversionFailureHandlingTrait implements Trait { + @Override + public TraitType type() { + return TraitType.DATA_TYPE_CONVERSION_FAILURE_HANDLING_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DefaultValueTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DefaultValueTrait.java index ccdbc6a3f76f..b293fe54e62b 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DefaultValueTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/DefaultValueTrait.java @@ -62,4 +62,9 @@ public static DefaultValueTrait create(Supplier supplier) { public static DefaultValueTrait idempotencyToken() { return new DefaultValueTrait(IdempotentUtils.getGenerator()); } + + @Override + public TraitType type() { + return TraitType.DEFAULT_VALUE_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/JsonValueTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/JsonValueTrait.java index d18aadf19b41..9d6279f44733 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/JsonValueTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/JsonValueTrait.java @@ -30,4 +30,9 @@ private JsonValueTrait() { public static JsonValueTrait create() { return new JsonValueTrait(); } + + @Override + public TraitType type() { + return TraitType.JSON_VALUE_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/ListTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/ListTrait.java index 825771f2fbb4..09d5eb9f82ae 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/ListTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/ListTrait.java @@ -63,6 +63,11 @@ public static Builder builder() { return new Builder(); } + @Override + public TraitType type() { + return TraitType.LIST_TRAIT; + } + public static final class Builder { private String memberLocationName; diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/LocationTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/LocationTrait.java index 419da0af5849..e5581ff68bad 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/LocationTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/LocationTrait.java @@ -57,6 +57,11 @@ public String unmarshallLocationName() { return unmarshallLocationName; } + @Override + public TraitType type() { + return TraitType.LOCATION_TRAIT; + } + /** * @return Builder instance. */ diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/MapTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/MapTrait.java index d37855814d72..20e7897b0f11 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/MapTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/MapTrait.java @@ -68,6 +68,11 @@ public static Builder builder() { return new Builder(); } + @Override + public TraitType type() { + return TraitType.MAP_TRAIT; + } + public static final class Builder { private String keyLocationName; diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/PayloadTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/PayloadTrait.java index 4b5725db4f1a..8847d98192ac 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/PayloadTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/PayloadTrait.java @@ -29,4 +29,9 @@ private PayloadTrait() { public static PayloadTrait create() { return new PayloadTrait(); } + + @Override + public TraitType type() { + return TraitType.PAYLOAD_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/RequiredTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/RequiredTrait.java index 9194a79abdad..fd854788181c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/RequiredTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/RequiredTrait.java @@ -29,4 +29,9 @@ private RequiredTrait() { public static RequiredTrait create() { return new RequiredTrait(); } + + @Override + public TraitType type() { + return TraitType.REQUIRED_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TimestampFormatTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TimestampFormatTrait.java index 18fdea2f6cc1..495735402f6c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TimestampFormatTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TimestampFormatTrait.java @@ -43,6 +43,11 @@ public static TimestampFormatTrait create(Format timestampFormat) { return new TimestampFormatTrait(timestampFormat); } + @Override + public TraitType type() { + return TraitType.TIMESTAMP_FORMAT_TRAIT; + } + /** * Enum of the timestamp formats we currently support. */ diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/Trait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/Trait.java index f85f2d04861e..6be323ffa05d 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/Trait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/Trait.java @@ -23,4 +23,12 @@ */ @SdkProtectedApi public interface Trait { + + /** + * The known trait type. This is correctly implemented and uniquely mapped to the enum values which allow us to create enum + * maps for trait known trait types. + */ + default TraitType type() { + return null; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TraitType.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TraitType.java new file mode 100644 index 000000000000..642fdc56df5e --- /dev/null +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/TraitType.java @@ -0,0 +1,84 @@ +/* + * 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.core.traits; + +import software.amazon.awssdk.annotations.SdkProtectedApi; + +/** + * Enumerates all the know traits. This enum is used to use EnumMap's for fast lookup + * of traits. + */ +@SdkProtectedApi +public enum TraitType { + DATA_TYPE_CONVERSION_FAILURE_HANDLING_TRAIT(DataTypeConversionFailureHandlingTrait.class), + DEFAULT_VALUE_TRAIT(DefaultValueTrait.class), + JSON_VALUE_TRAIT(JsonValueTrait.class), + LIST_TRAIT(ListTrait.class), + LOCATION_TRAIT(LocationTrait.class), + MAP_TRAIT(MapTrait.class), + PAYLOAD_TRAIT(PayloadTrait.class), + REQUIRED_TRAIT(RequiredTrait.class), + TIMESTAMP_FORMAT_TRAIT(TimestampFormatTrait.class), + XML_ATTRIBUTE_TRAIT(XmlAttributeTrait.class), + XML_ATTRIBUTES_TRAIT(XmlAttributesTrait.class), + ; + + private final Class typeClass; + + TraitType(Class typeClass) { + this.typeClass = typeClass; + } + + /** + * Returns the type for the given class. + */ + public static TraitType from(Class clazz) { + if (clazz == DataTypeConversionFailureHandlingTrait.class) { + return DATA_TYPE_CONVERSION_FAILURE_HANDLING_TRAIT; + } + if (clazz == DefaultValueTrait.class) { + return DEFAULT_VALUE_TRAIT; + } + if (clazz == JsonValueTrait.class) { + return JSON_VALUE_TRAIT; + } + if (clazz == ListTrait.class) { + return LIST_TRAIT; + } + if (clazz == LocationTrait.class) { + return LOCATION_TRAIT; + } + if (clazz == MapTrait.class) { + return MAP_TRAIT; + } + if (clazz == PayloadTrait.class) { + return PAYLOAD_TRAIT; + } + if (clazz == RequiredTrait.class) { + return REQUIRED_TRAIT; + } + if (clazz == TimestampFormatTrait.class) { + return TIMESTAMP_FORMAT_TRAIT; + } + if (clazz == XmlAttributeTrait.class) { + return XML_ATTRIBUTE_TRAIT; + } + if (clazz == XmlAttributesTrait.class) { + return XML_ATTRIBUTES_TRAIT; + } + return null; + } +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributeTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributeTrait.java index f0b0ec462f00..c968fc197f87 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributeTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributeTrait.java @@ -30,4 +30,9 @@ public static XmlAttributeTrait create() { return new XmlAttributeTrait(); } + + @Override + public TraitType type() { + return TraitType.XML_ATTRIBUTE_TRAIT; + } } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributesTrait.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributesTrait.java index f63f9bf27949..8426a27bee85 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributesTrait.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/traits/XmlAttributesTrait.java @@ -45,6 +45,11 @@ public Map attributes() { return attributes; } + @Override + public TraitType type() { + return TraitType.XML_ATTRIBUTES_TRAIT; + } + public static final class AttributeAccessors { private final Function attributeGetter; diff --git a/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/serialization/TransferManagerJsonUnmarshaller.java b/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/serialization/TransferManagerJsonUnmarshaller.java index da61e48cf6c3..66ebf3cd7c9e 100644 --- a/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/serialization/TransferManagerJsonUnmarshaller.java +++ b/services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/internal/serialization/TransferManagerJsonUnmarshaller.java @@ -29,6 +29,7 @@ import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.traits.MapTrait; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.protocols.jsoncore.JsonNode; import software.amazon.awssdk.utils.BinaryUtils; import software.amazon.awssdk.utils.DateUtils; @@ -85,7 +86,7 @@ public Map unmarshall(JsonNode jsonContent, SdkField field) { return null; } - SdkField valueInfo = field.getTrait(MapTrait.class).valueFieldInfo(); + SdkField valueInfo = field.getTrait(MapTrait.class, TraitType.MAP_TRAIT).valueFieldInfo(); Map map = new HashMap<>(); jsonContent.asObject().forEach((fieldName, value) -> {