diff --git a/aws/client/aws-client-awsjson/build.gradle.kts b/aws/client/aws-client-awsjson/build.gradle.kts index 1e3af0971..3024526ca 100644 --- a/aws/client/aws-client-awsjson/build.gradle.kts +++ b/aws/client/aws-client-awsjson/build.gradle.kts @@ -20,3 +20,4 @@ dependencies { val generator = "software.amazon.smithy.java.protocoltests.generators.ProtocolTestGenerator" addGenerateSrcsTask(generator, "awsJson1_0", "aws.protocoltests.json10#JsonRpc10") +addGenerateSrcsTask(generator, "awsJson1_1", "aws.protocoltests.json#JsonProtocol") diff --git a/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson11ProtocolTests.java b/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson11ProtocolTests.java new file mode 100644 index 000000000..5183f3960 --- /dev/null +++ b/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson11ProtocolTests.java @@ -0,0 +1,41 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.aws.jsonprotocols; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.charset.StandardCharsets; +import software.amazon.smithy.java.io.ByteBufferUtils; +import software.amazon.smithy.java.io.datastream.DataStream; +import software.amazon.smithy.java.protocoltests.harness.*; +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; + +@ProtocolTest( + service = "aws.protocoltests.json#JsonProtocol", + testType = TestType.CLIENT) +public class AwsJson11ProtocolTests { + @HttpClientRequestTests + @ProtocolTestFilter( + skipTests = { + "SDKAppliedContentEncoding_awsJson1_1", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", + }) + public void requestTest(DataStream expected, DataStream actual) { + Node expectedNode = ObjectNode.objectNode(); + if (expected.contentLength() != 0) { + expectedNode = Node.parse(new String(ByteBufferUtils.getBytes(expected.asByteBuffer()), + StandardCharsets.UTF_8)); + } + Node actualNode = Node.parse(new StringBuildingSubscriber(actual).getResult()); + assertEquals(expectedNode, actualNode); + } + + @HttpClientResponseTests + public void responseTest(Runnable test) { + test.run(); + } +} diff --git a/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson1ProtocolTests.java b/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson1ProtocolTests.java index 36d4cf867..4f2885241 100644 --- a/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson1ProtocolTests.java +++ b/aws/client/aws-client-awsjson/src/it/java/software/amazon/smithy/java/client/aws/jsonprotocols/AwsJson1ProtocolTests.java @@ -51,12 +51,6 @@ public void requestTest(DataStream expected, DataStream actual) { skipTests = { "AwsJson10ClientPopulatesDefaultsValuesWhenMissingInResponse", "AwsJson10ClientIgnoresDefaultValuesIfMemberValuesArePresentInResponse", - //The below fail because we haven't implemented code based exception handling - "AwsJson10FooErrorUsingCode", - "AwsJson10FooErrorUsingCodeAndNamespace", - "AwsJson10FooErrorUsingCodeUriAndNamespace", - "AwsJson10FooErrorWithDunderTypeUriAndNamespace" - }, skipOperations = "aws.protocoltests.json10#OperationWithRequiredMembersWithDefaults") public void responseTest(Runnable test) { diff --git a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson11Protocol.java b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson11Protocol.java index d69a3a2a1..cee547540 100644 --- a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson11Protocol.java +++ b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson11Protocol.java @@ -10,6 +10,7 @@ import software.amazon.smithy.java.client.core.ClientProtocol; import software.amazon.smithy.java.client.core.ClientProtocolFactory; import software.amazon.smithy.java.client.core.ProtocolSettings; +import software.amazon.smithy.java.client.http.HttpErrorDeserializer; import software.amazon.smithy.model.shapes.ShapeId; /** @@ -24,7 +25,7 @@ public final class AwsJson11Protocol extends AwsJsonProtocol { * discriminator of documents that use relative shape IDs. */ public AwsJson11Protocol(ShapeId service) { - super(TRAIT_ID, service); + super(TRAIT_ID, service, HttpErrorDeserializer.DEFAULT_ERROR_PAYLOAD_PARSER); } @Override diff --git a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson1Protocol.java b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson1Protocol.java index 1fa56271a..b28b6b639 100644 --- a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson1Protocol.java +++ b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJson1Protocol.java @@ -10,6 +10,9 @@ import software.amazon.smithy.java.client.core.ClientProtocol; import software.amazon.smithy.java.client.core.ClientProtocolFactory; import software.amazon.smithy.java.client.core.ProtocolSettings; +import software.amazon.smithy.java.client.http.ErrorTypeUtils; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.core.serde.document.DocumentDeserializer; import software.amazon.smithy.model.shapes.ShapeId; /** @@ -24,7 +27,13 @@ public final class AwsJson1Protocol extends AwsJsonProtocol { * discriminator of documents that use relative shape IDs. */ public AwsJson1Protocol(ShapeId service) { - super(TRAIT_ID, service); + super(TRAIT_ID, service, AwsJson1Protocol::extractErrorType); + } + + private static ShapeId extractErrorType(Document document, String namespace) { + return DocumentDeserializer.parseDiscriminator( + ErrorTypeUtils.removeUri(ErrorTypeUtils.readTypeAndCode(document)), + namespace); } @Override diff --git a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJsonProtocol.java b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJsonProtocol.java index 05703ef5e..b76b42c3b 100644 --- a/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJsonProtocol.java +++ b/aws/client/aws-client-awsjson/src/main/java/software/amazon/smithy/java/aws/client/awsjson/AwsJsonProtocol.java @@ -39,14 +39,22 @@ abstract sealed class AwsJsonProtocol extends HttpClientProtocol permits AwsJson * @param service The service ID used to make X-Amz-Target, and the namespace is used when finding the * discriminator of documents that use relative shape IDs. */ - public AwsJsonProtocol(ShapeId trait, ShapeId service) { + public AwsJsonProtocol( + ShapeId trait, + ShapeId service, + HttpErrorDeserializer.ErrorPayloadParser errorPayloadParser + ) { super(trait); this.service = service; - this.codec = JsonCodec.builder().defaultNamespace(service.getNamespace()).build(); + this.codec = JsonCodec.builder() + .defaultNamespace(service.getNamespace()) + .useTimestampFormat(true) + .build(); this.errorDeserializer = HttpErrorDeserializer.builder() .codec(codec) .serviceId(service) + .errorPayloadParser(errorPayloadParser) .headerErrorExtractor(new AmznErrorHeaderExtractor()) .build(); } diff --git a/aws/client/aws-client-restjson/src/it/java/software/amazon/smithy/java/client/aws/restjson/RestJson1ProtocolTests.java b/aws/client/aws-client-restjson/src/it/java/software/amazon/smithy/java/client/aws/restjson/RestJson1ProtocolTests.java index e5dc54b93..f41c1c1e8 100644 --- a/aws/client/aws-client-restjson/src/it/java/software/amazon/smithy/java/client/aws/restjson/RestJson1ProtocolTests.java +++ b/aws/client/aws-client-restjson/src/it/java/software/amazon/smithy/java/client/aws/restjson/RestJson1ProtocolTests.java @@ -56,13 +56,6 @@ public void requestTest(DataStream expected, DataStream actual) { } @HttpClientResponseTests - @ProtocolTestFilter( - skipTests = { - "RestJsonFooErrorUsingCode", - "RestJsonFooErrorUsingCodeAndNamespace", - "RestJsonFooErrorUsingCodeUriAndNamespace", - "RestJsonFooErrorWithDunderTypeUriAndNamespace" - }) public void responseTest(Runnable test) { test.run(); } diff --git a/aws/client/aws-client-restxml/src/main/java/software/amazon/smithy/java/aws/client/restxml/RestXmlClientProtocol.java b/aws/client/aws-client-restxml/src/main/java/software/amazon/smithy/java/aws/client/restxml/RestXmlClientProtocol.java index 40fda578e..32f87cbf7 100644 --- a/aws/client/aws-client-restxml/src/main/java/software/amazon/smithy/java/aws/client/restxml/RestXmlClientProtocol.java +++ b/aws/client/aws-client-restxml/src/main/java/software/amazon/smithy/java/aws/client/restxml/RestXmlClientProtocol.java @@ -18,11 +18,13 @@ import software.amazon.smithy.java.client.http.binding.HttpBindingClientProtocol; import software.amazon.smithy.java.client.http.binding.HttpBindingErrorFactory; import software.amazon.smithy.java.context.Context; +import software.amazon.smithy.java.core.error.CallException; import software.amazon.smithy.java.core.error.ModeledException; import software.amazon.smithy.java.core.schema.InputEventStreamingApiOperation; import software.amazon.smithy.java.core.schema.OutputEventStreamingApiOperation; import software.amazon.smithy.java.core.serde.Codec; import software.amazon.smithy.java.core.serde.TypeRegistry; +import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.java.core.serde.event.EventDecoderFactory; import software.amazon.smithy.java.core.serde.event.EventEncoderFactory; import software.amazon.smithy.java.core.serde.event.EventStreamingException; @@ -95,24 +97,34 @@ protected EventDecoderFactory getEventDecoderFactory( return AwsEventDecoderFactory.forOutputStream(outputOperation, payloadCodec(), f -> f); } - private static final HttpErrorDeserializer.ErrorPayloadParser XML_ERROR_PAYLOAD_PARSER = ( - Context context, - Codec codec, - HttpErrorDeserializer.KnownErrorFactory knownErrorFactory, - ShapeId serviceId, - TypeRegistry typeRegistry, - HttpResponse response, - ByteBuffer buffer) -> { - var deserializer = codec.createDeserializer(buffer); - String code = XmlUtil.parseErrorCodeName(deserializer); - var nameSpace = serviceId.getNamespace(); - var id = ShapeId.fromOptionalNamespace(nameSpace, code); - var builder = typeRegistry.createBuilder(id, ModeledException.class); - if (builder != null) { - return knownErrorFactory.createError(context, codec, response, builder); - } - return null; - }; + private static final HttpErrorDeserializer.ErrorPayloadParser XML_ERROR_PAYLOAD_PARSER = + new HttpErrorDeserializer.ErrorPayloadParser() { + @Override + public CallException parsePayload( + Context context, + Codec codec, + HttpErrorDeserializer.KnownErrorFactory knownErrorFactory, + ShapeId serviceId, + TypeRegistry typeRegistry, + HttpResponse response, + ByteBuffer buffer + ) { + var deserializer = codec.createDeserializer(buffer); + String code = XmlUtil.parseErrorCodeName(deserializer); + var nameSpace = serviceId.getNamespace(); + var id = ShapeId.fromOptionalNamespace(nameSpace, code); + var builder = typeRegistry.createBuilder(id, ModeledException.class); + if (builder != null) { + return knownErrorFactory.createError(context, codec, response, builder); + } + return null; + } + + @Override + public ShapeId extractErrorType(Document document, String namespace) { + return null; + } + }; public static final class Factory implements ClientProtocolFactory { @Override diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/ErrorTypeUtils.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/ErrorTypeUtils.java new file mode 100644 index 000000000..34892bc0f --- /dev/null +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/ErrorTypeUtils.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.model.shapes.ShapeType; + +public final class ErrorTypeUtils { + + private ErrorTypeUtils() {} + + /** + * Read the error type from __type field of the document. + * + * @param document the document of the payload to read. + * @return the extracted error type from the document. + */ + public static String readType(Document document) { + String errorType = null; + var member = document.getMember("__type"); + if (member != null && member.type() == ShapeType.STRING) { + errorType = member.asString(); + } + return errorType; + } + + /** + * Read the error type from __type or code field of the document. + * + * @param document the document of the payload to read. + * @return the extracted error type from the document. + */ + public static String readTypeAndCode(Document document) { + String errorType = readType(document); + if (errorType == null) { + var member = document.getMember("code"); + if (member != null && member.type() == ShapeType.STRING) { + errorType = member.asString(); + } + } + return errorType; + } + + /** + * Removes the trailing URI in {@code __type} field or {@code code} field of the document. + * + *

For example, given {@code __type = "aws.protocoltests.restjson#FooError:http://abc.com"}, + * protocols like restJSON should ignore the trailing URI and keep the namespace of the error type. + * + * @param text The error type string. + * @return The error type string without the trailing URI. + */ + public static String removeUri(String text) { + if (text == null) { + return null; + } + var colon = text.indexOf(':'); + if (colon > 0) { + text = text.substring(0, colon); + } + return text; + } + + /** + * Removes the namespace and trailing URI in {@code __type} field or {@code code} field of the document. + * + *

For example, given {@code __type = "aws.protocoltests.restjson#FooError:http://abc.com"}, + * protocols like awsJSON 1.1 should ignore the namespace and the trailing URI of the error type. + * + * @param text The error type string. + * @return The error type string without the trailing URI. + */ + public static String removeNamespaceAndUri(String text) { + if (text == null) { + return null; + } + var hash = text.indexOf('#'); + if (hash > 0) { + text = text.substring(hash + 1); + } + return removeUri(text); + } +} diff --git a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/HttpErrorDeserializer.java b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/HttpErrorDeserializer.java index cb276721a..f790a5e45 100644 --- a/client/client-http/src/main/java/software/amazon/smithy/java/client/http/HttpErrorDeserializer.java +++ b/client/client-http/src/main/java/software/amazon/smithy/java/client/http/HttpErrorDeserializer.java @@ -17,6 +17,7 @@ import software.amazon.smithy.java.core.serde.TypeRegistry; import software.amazon.smithy.java.core.serde.document.DiscriminatorException; import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.core.serde.document.DocumentDeserializer; import software.amazon.smithy.java.http.api.HttpResponse; import software.amazon.smithy.java.io.datastream.DataStream; import software.amazon.smithy.model.shapes.ShapeId; @@ -132,7 +133,7 @@ public interface ErrorPayloadParser { * * @return the created error. */ - CallException parsePayload( + default CallException parsePayload( Context context, Codec codec, KnownErrorFactory knownErrorFactory, @@ -140,7 +141,33 @@ CallException parsePayload( TypeRegistry typeRegistry, HttpResponse response, ByteBuffer buffer - ) throws SerializationException, DiscriminatorException; + ) { + var document = codec.createDeserializer(buffer).readDocument(); + var id = extractErrorType(document, serviceId.getNamespace()); + var builder = typeRegistry.createBuilder(id, ModeledException.class); + if (builder != null) { + return knownErrorFactory.createErrorFromDocument( + context, + codec, + response, + buffer, + document, + builder); + } + return null; + } + + /** + * This method should extract the error type from converted document based on the + * protocol requirement from either __type or code and apply necessary sanitizing to + * the error type. + * + * @param document The converted document of the payload. + * @param namespace The default namespace used for error type's ShapeId. + * + * @return the created error. + */ + ShapeId extractErrorType(Document document, String namespace); } // Does not check for any error headers by default. @@ -191,30 +218,12 @@ public ModeledException createErrorFromDocument( } }; - // This default parser should work for most protocols, but other protocols + // This default parser should work for most protocols, but other protocols // that do not support document types will need a custom parser to extract error ShapeId. - private static final ErrorPayloadParser DEFAULT_ERROR_PAYLOAD_PARSER = ( - Context context, - Codec codec, - KnownErrorFactory knownErrorFactory, - ShapeId serviceId, - TypeRegistry typeRegistry, - HttpResponse response, - ByteBuffer buffer) -> { - var document = codec.createDeserializer(buffer).readDocument(); - var id = document.discriminator(); - var builder = typeRegistry.createBuilder(id, ModeledException.class); - if (builder != null) { - return knownErrorFactory.createErrorFromDocument( - context, - codec, - response, - buffer, - document, - builder); - } - return null; - }; + public static final ErrorPayloadParser DEFAULT_ERROR_PAYLOAD_PARSER = + (document, namespace) -> DocumentDeserializer.parseDiscriminator( + ErrorTypeUtils.removeNamespaceAndUri(ErrorTypeUtils.readTypeAndCode(document)), + namespace); private final Codec codec; private final HeaderErrorExtractor headerErrorExtractor; diff --git a/client/client-http/src/test/java/software/amazon/smithy/java/client/http/ErrorTypeUtilsTest.java b/client/client-http/src/test/java/software/amazon/smithy/java/client/http/ErrorTypeUtilsTest.java new file mode 100644 index 000000000..22a341c47 --- /dev/null +++ b/client/client-http/src/test/java/software/amazon/smithy/java/client/http/ErrorTypeUtilsTest.java @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.client.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.java.core.serde.document.Document; + +public class ErrorTypeUtilsTest { + private static final String SIMPLE_TYPE = "FooError"; + private static final String TYPE_WITH_URI = "FooError:http://amazon.com/smithy/com.amazon.smithy.validate/"; + private static final String TYPE_WITH_NAMESPACE = "aws.protocoltests.restjson#FooError"; + private static final String TYPE_WITH_NAMESPACE_AND_URI = + "aws.protocoltests.restjson#FooError:http://amazon.com/smithy/com.amazon.smithy.validate/"; + + @Test + public void testRemoveUri() { + String expected = "FooError"; + String expectedWithNamespace = "aws.protocoltests.restjson#FooError"; + + assertEquals(expected, ErrorTypeUtils.removeUri(SIMPLE_TYPE)); + assertEquals(expected, ErrorTypeUtils.removeUri(TYPE_WITH_URI)); + assertEquals(expectedWithNamespace, ErrorTypeUtils.removeUri(TYPE_WITH_NAMESPACE)); + assertEquals(expectedWithNamespace, ErrorTypeUtils.removeUri(TYPE_WITH_NAMESPACE_AND_URI)); + } + + @Test + public void testRemoveNameSpaceAndUri() { + String expected = "FooError"; + + assertEquals(expected, ErrorTypeUtils.removeNamespaceAndUri(SIMPLE_TYPE)); + assertEquals(expected, ErrorTypeUtils.removeNamespaceAndUri(TYPE_WITH_URI)); + assertEquals(expected, ErrorTypeUtils.removeNamespaceAndUri(TYPE_WITH_NAMESPACE)); + assertEquals(expected, ErrorTypeUtils.removeNamespaceAndUri(TYPE_WITH_NAMESPACE_AND_URI)); + } + + @Test + public void testReadType() { + var document = Document.of(Map.of("__type", Document.of("foo"))); + assertEquals("foo", ErrorTypeUtils.readType(document)); + } + + @Test + public void testReadTypeAndCode() { + var document1 = Document.of(Map.of("__type", Document.of("foo"), "code", Document.of("bar"))); + var document2 = Document.of(Map.of("code", Document.of("bar"))); + + assertEquals("foo", ErrorTypeUtils.readTypeAndCode(document1)); + assertEquals("bar", ErrorTypeUtils.readTypeAndCode(document2)); + } + + @Test + public void testWrongTypeIgnored() { + var document = Document.of(Map.of("__type", Document.of(123))); + + assertNull(ErrorTypeUtils.readType(document)); + } +} diff --git a/client/client-rpcv2-cbor/src/main/java/software/amazon/smithy/java/client/rpcv2/RpcV2CborProtocol.java b/client/client-rpcv2-cbor/src/main/java/software/amazon/smithy/java/client/rpcv2/RpcV2CborProtocol.java index a93571e2b..2211a0ebc 100644 --- a/client/client-rpcv2-cbor/src/main/java/software/amazon/smithy/java/client/rpcv2/RpcV2CborProtocol.java +++ b/client/client-rpcv2-cbor/src/main/java/software/amazon/smithy/java/client/rpcv2/RpcV2CborProtocol.java @@ -17,6 +17,7 @@ import software.amazon.smithy.java.client.core.ClientProtocol; import software.amazon.smithy.java.client.core.ClientProtocolFactory; import software.amazon.smithy.java.client.core.ProtocolSettings; +import software.amazon.smithy.java.client.http.ErrorTypeUtils; import software.amazon.smithy.java.client.http.HttpClientProtocol; import software.amazon.smithy.java.client.http.HttpErrorDeserializer; import software.amazon.smithy.java.context.Context; @@ -27,6 +28,8 @@ import software.amazon.smithy.java.core.schema.Unit; import software.amazon.smithy.java.core.serde.Codec; import software.amazon.smithy.java.core.serde.TypeRegistry; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.java.core.serde.document.DocumentDeserializer; import software.amazon.smithy.java.core.serde.event.EventDecoderFactory; import software.amazon.smithy.java.core.serde.event.EventEncoderFactory; import software.amazon.smithy.java.core.serde.event.EventStreamingException; @@ -51,7 +54,11 @@ public final class RpcV2CborProtocol extends HttpClientProtocol { public RpcV2CborProtocol(ShapeId service) { super(Rpcv2CborTrait.ID); this.service = service; - this.errorDeserializer = HttpErrorDeserializer.builder().codec(CBOR_CODEC).serviceId(service).build(); + this.errorDeserializer = HttpErrorDeserializer.builder() + .codec(CBOR_CODEC) + .serviceId(service) + .errorPayloadParser(RpcV2CborProtocol::extractErrorType) + .build(); } @Override @@ -163,6 +170,12 @@ private EventDecoderFactory getEventDecoderFactory( return AwsEventDecoderFactory.forOutputStream(outputOperation, payloadCodec(), f -> f); } + private static ShapeId extractErrorType(Document document, String namespace) { + return DocumentDeserializer.parseDiscriminator( + ErrorTypeUtils.removeUri(ErrorTypeUtils.readType(document)), + namespace); + } + public static final class Factory implements ClientProtocolFactory { @Override public ShapeId id() {