From 26e26b514a116bae3165450ccecfa26f50715f8f Mon Sep 17 00:00:00 2001 From: John Viegas Date: Thu, 14 Jan 2021 21:19:43 -0800 Subject: [PATCH] Support to UnMarshall Blob type payload data in XMlProtocol --- .../unmarshall/XmlProtocolUnmarshaller.java | 15 +++++++++++-- .../unmarshall/XmlResponseParserUtils.java | 22 ++++++++++++++++++- .../json/internal/MarshallerUtil.java | 0 .../suites/cases/rest-core-output.json | 20 ++++++++++++++++- .../suites/cases/rest-json-output.json | 19 ---------------- 5 files changed, 53 insertions(+), 23 deletions(-) rename core/protocols/{aws-json-protocol => protocol-core}/src/main/java/software/amazon/awssdk/protocols/json/internal/MarshallerUtil.java (100%) 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 9429422a1050..ad3ffddc9365 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 @@ -16,13 +16,16 @@ package software.amazon.awssdk.protocols.xml.internal.unmarshall; import static java.util.Collections.singletonList; +import static software.amazon.awssdk.protocols.xml.internal.unmarshall.XmlResponseParserUtils.getBlobTypePayloadMemberToUnmarshal; import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.protocol.MarshallLocation; @@ -76,6 +79,7 @@ public TypeT unmarshall(SdkPojo sdkPojo, } SdkPojo unmarshall(XmlUnmarshallerContext context, SdkPojo sdkPojo, XmlElement root) { + Optional> payloadMemberAsBlobType = getBlobTypePayloadMemberToUnmarshal(sdkPojo); for (SdkField field : sdkPojo.sdkFields()) { XmlUnmarshaller unmarshaller = REGISTRY.getUnmarshaller(field.location(), field.marshallingType()); @@ -94,8 +98,15 @@ SdkPojo unmarshall(XmlUnmarshallerContext context, SdkPojo sdkPojo, XmlElement r root.getElementsByName(field.unmarshallLocationName()); if (!CollectionUtils.isNullOrEmpty(element)) { - Object unmarshalled = unmarshaller.unmarshall(context, element, (SdkField) field); - field.set(sdkPojo, unmarshalled); + boolean isFieldBlobTypePayload = payloadMemberAsBlobType.isPresent() + && payloadMemberAsBlobType.get().equals(field); + + if (isFieldBlobTypePayload) { + field.set(sdkPojo, SdkBytes.fromInputStream(context.response().content().get())); + } else { + Object unmarshalled = unmarshaller.unmarshall(context, element, (SdkField) field); + field.set(sdkPojo, unmarshalled); + } } } } else { 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 97023b37709b..531877973e4f 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 @@ -19,8 +19,11 @@ import java.util.Optional; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.SdkField; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.PayloadTrait; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.SdkHttpFullResponse; import software.amazon.awssdk.protocols.query.unmarshall.XmlDomParser; @@ -49,7 +52,7 @@ public static XmlElement parse(SdkPojo sdkPojo, SdkHttpFullResponse response) { // In some cases the responseContent is present but empty, so when we are not expecting a body we should // not attempt to parse it even if the body appears to be present. if ((!response.isSuccessful() || hasPayloadMembers(sdkPojo)) && responseContent.isPresent() && - !contentLengthZero(response)) { + !contentLengthZero(response) && !getBlobTypePayloadMemberToUnmarshal(sdkPojo).isPresent()) { return XmlDomParser.parse(responseContent.get()); } else { return XmlElement.empty(); @@ -63,6 +66,21 @@ public static XmlElement parse(SdkPojo sdkPojo, SdkHttpFullResponse response) { } } + /** + * Gets the Member which is a Payload and which is of Blob Type. + * @param sdkPojo + * @return Optional of SdkField member if member is Blob type payload else returns Empty. + */ + public static Optional> getBlobTypePayloadMemberToUnmarshal(SdkPojo sdkPojo) { + return sdkPojo.sdkFields().stream() + .filter(e -> isExplicitPayloadMember(e)) + .filter(f -> f.marshallingType() == MarshallingType.SDK_BYTES).findFirst(); + } + + private static boolean isExplicitPayloadMember(SdkField f) { + return f.containsTrait(PayloadTrait.class); + } + private static boolean hasPayloadMembers(SdkPojo sdkPojo) { return sdkPojo.sdkFields().stream() .anyMatch(f -> f.location() == MarshallLocation.PAYLOAD); @@ -71,4 +89,6 @@ private static boolean hasPayloadMembers(SdkPojo sdkPojo) { private static boolean contentLengthZero(SdkHttpFullResponse response) { return response.firstMatchingHeader(CONTENT_LENGTH).map(l -> Long.parseLong(l) == 0).orElse(false); } + + } diff --git a/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/MarshallerUtil.java b/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/json/internal/MarshallerUtil.java similarity index 100% rename from core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/MarshallerUtil.java rename to core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/json/internal/MarshallerUtil.java diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-core-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-core-output.json index e60f20bea5bb..4b6cad3e326f 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-core-output.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-core-output.json @@ -119,8 +119,26 @@ "deserializedAs": { } } - } + }, // TODO header maps, service models supports this but Java SDK does not (not currently exercised) // TODO header maps with prefix, services models do not support this, only used by S3 // TODO List of strings bound to header, service models supports this, not currently exercised by any service + { + "description": "Operation with explicit payload blob in output is unmarshalled correctly", + "given": { + "response": { + "status_code": 200, + "body": "contents" + } + }, + "when": { + "action": "unmarshall", + "operation": "OperationWithExplicitPayloadBlob" + }, + "then": { + "deserializedAs": { + "PayloadMember": "contents" + } + } + } ] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-json-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-json-output.json index 2ea331b183e4..c5e2da8ba2db 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-json-output.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-json-output.json @@ -19,25 +19,6 @@ } } }, - // TODO payload blob and streaming should be moved up to rest-core when Java supports it - { - "description": "Operation with explicit payload blob in output is unmarshalled correctly", - "given": { - "response": { - "status_code": 200, - "body": "contents" - } - }, - "when": { - "action": "unmarshall", - "operation": "OperationWithExplicitPayloadBlob" - }, - "then": { - "deserializedAs": { - "PayloadMember": "contents" - } - } - }, { "description": "Operation with streaming payload in output is unmarshalled correctly", "given": {