From 0d997dff95f9fdedb7099b23a19689a6616a1fed 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 20:27:37 -0700 Subject: [PATCH] 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 +- .../protocols/core/InstantToString.java | 3 +- .../protocols/core/NumberToInstant.java | 3 +- .../protocols/core/StringToInstant.java | 3 +- .../software/amazon/awssdk/core/SdkField.java | 111 ++++++++++++++++-- ...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 +- 36 files changed, 315 insertions(+), 47 deletions(-) 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..71ff44fc7ab2 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 @@ -34,6 +34,7 @@ import software.amazon.awssdk.core.document.Document; import software.amazon.awssdk.core.protocol.MarshallLocation; import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.TraitType; import software.amazon.awssdk.core.traits.ListTrait; import software.amazon.awssdk.core.traits.MapTrait; import software.amazon.awssdk.core.traits.PayloadTrait; @@ -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/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..0ecfa5571fcf 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 @@ -21,6 +21,7 @@ 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.TraitType; import software.amazon.awssdk.core.traits.TimestampFormatTrait; /** @@ -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..6251bcbb4e35 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 @@ -22,6 +22,7 @@ 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.TraitType; import software.amazon.awssdk.core.traits.TimestampFormatTrait; 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/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) -> {