From 613f26627f0004fc0197b4abc54c2f6b5337f05f Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 18 May 2020 12:26:50 -0700 Subject: [PATCH 1/4] Adding more flexible support for encodings. --- .../util/serializer/SerializerEncoding.java | 74 ++++++++++++++++--- .../serializer/SerializerEncodingTests.java | 57 ++++++++++++++ 2 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/SerializerEncodingTests.java diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java index 4fdc7326e962..8b028af4d4d9 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java @@ -3,8 +3,13 @@ package com.azure.core.util.serializer; - import com.azure.core.http.HttpHeaders; +import com.azure.core.util.logging.ClientLogger; + +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; /** * Supported serialization encoding formats. @@ -20,21 +25,70 @@ public enum SerializerEncoding { */ XML; + private static final ClientLogger LOGGER = new ClientLogger(SerializerEncoding.class); + private static final String CONTENT_TYPE = "Content-Type"; + private static final Map SUPPORTED_MIME_TYPES; + private static final TreeMap SUPPORTED_SUFFIXES; + private static final SerializerEncoding DEFAULT_ENCODING = JSON; + + + static { + // Encodings and suffixes from: https://tools.ietf.org/html/rfc6838 + final Comparator comparator = Comparator.comparing(Function.identity(), String::compareToIgnoreCase); + + SUPPORTED_MIME_TYPES = new TreeMap<>(comparator); + SUPPORTED_MIME_TYPES.put("text/xml", XML); + SUPPORTED_MIME_TYPES.put("application/xml", XML); + SUPPORTED_MIME_TYPES.put("application/json", JSON); + + SUPPORTED_SUFFIXES = new TreeMap<>(comparator); + SUPPORTED_SUFFIXES.put("xml", XML); + SUPPORTED_SUFFIXES.put("json", JSON); + } + /** * Determines the serializer encoding to use based on the Content-Type header. * - * @param headers the headers to check the encoding for - * @return the serializer encoding to use for the body + * @param headers the headers to check the encoding for. + * @return the serializer encoding to use for the body. {@link #JSON} if there is no Content-Type header or an + * unrecognized Content-Type encoding is returned. */ public static SerializerEncoding fromHeaders(HttpHeaders headers) { - String mimeContentType = headers.getValue("Content-Type"); - if (mimeContentType != null) { - String[] parts = mimeContentType.split(";"); - if (parts[0].equalsIgnoreCase("application/xml") || parts[0].equalsIgnoreCase("text/xml")) { - return XML; - } + final String mimeContentType = headers.getValue(CONTENT_TYPE); + if (mimeContentType == null || mimeContentType.isEmpty()) { + LOGGER.warning("'{}' not found. Returning default encoding: {}", CONTENT_TYPE, DEFAULT_ENCODING); + return DEFAULT_ENCODING; } - return JSON; + final SerializerEncoding encoding = SUPPORTED_MIME_TYPES.get(mimeContentType); + if (encoding != null) { + return encoding; + } + + final String[] parts = mimeContentType.split(";"); + final String[] mimeTypeParts = parts[0].split("/"); + if (mimeTypeParts.length != 2) { + LOGGER.warning("Content-Type '{}' does not match mime-type formatting 'type'/'subtype'. " + + "Returning default: {}", parts[0], DEFAULT_ENCODING); + return DEFAULT_ENCODING; + } + + // Check the suffix if it does not match the full types. + final String subtype = mimeTypeParts[1]; + final int lastIndex = subtype.lastIndexOf("+"); + if (lastIndex == -1) { + return DEFAULT_ENCODING; + } + + final String mimeTypeSuffix = subtype.substring(lastIndex + 1); + final SerializerEncoding serializerEncoding = SUPPORTED_SUFFIXES.get(mimeTypeSuffix); + if (serializerEncoding != null) { + return serializerEncoding; + } + + LOGGER.warning("Content-Type '{}' does not match any supported one. Returning default: {}", + mimeContentType, DEFAULT_ENCODING); + + return DEFAULT_ENCODING; } } diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/SerializerEncodingTests.java b/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/SerializerEncodingTests.java new file mode 100644 index 000000000000..06f425da099d --- /dev/null +++ b/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/SerializerEncodingTests.java @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.core.util.serializer; + +import com.azure.core.http.HttpHeaders; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Collections; + +/** + * Tests for {@link SerializerEncoding}. + */ +class SerializerEncodingTests { + private static final String CONTENT_TYPE = "Content-Type"; + + @ParameterizedTest + @ValueSource(strings = {"application/xml", "application/atom+xml", "text/xml", "application/foo+XML", "TEXT/XML"}) + void recognizeXml(String mimeType) { + // Arrange + HttpHeaders headers = new HttpHeaders(Collections.singletonMap(CONTENT_TYPE, mimeType)); + + // Act & Assert + Assertions.assertEquals(SerializerEncoding.XML, SerializerEncoding.fromHeaders(headers)); + } + + @ParameterizedTest + @ValueSource(strings = {"application/json", "application/kv+json", "APPLICATION/JSON", "application/FOO+JSON"}) + void recognizeJson(String mimeType) { + // Arrange + HttpHeaders headers = new HttpHeaders(Collections.singletonMap(CONTENT_TYPE, mimeType)); + + // Act & Assert + Assertions.assertEquals(SerializerEncoding.JSON, SerializerEncoding.fromHeaders(headers)); + } + + @Test + void defaultNoContentType() { + // Arrange + HttpHeaders headers = new HttpHeaders(Collections.singletonMap("Http-Method", "GET")); + + // Act & Assert + Assertions.assertEquals(SerializerEncoding.JSON, SerializerEncoding.fromHeaders(headers)); + } + + @ParameterizedTest + @ValueSource(strings = {"application/binary", "invalid-mime-type"}) + void defaultUnsupportedType(String mimeType) { + // Arrange + HttpHeaders headers = new HttpHeaders(Collections.singletonMap(CONTENT_TYPE, mimeType)); + + // Act & Assert + Assertions.assertEquals(SerializerEncoding.JSON, SerializerEncoding.fromHeaders(headers)); + } +} From 9a9cbe9546597aefb7f51e7e638fe1feaab6e5ee Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 18 May 2020 13:45:18 -0700 Subject: [PATCH 2/4] Add suppression. --- .../src/main/resources/checkstyle/checkstyle-suppressions.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index 9dccb5286e34..6daa15d8eed0 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -239,6 +239,7 @@ + From 3235bdc30482f381dbf2c16ec08078a434d9f9af Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 18 May 2020 14:16:59 -0700 Subject: [PATCH 3/4] Change compator --- .../com/azure/core/util/serializer/SerializerEncoding.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java index 8b028af4d4d9..76dfdd956333 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java @@ -34,14 +34,12 @@ public enum SerializerEncoding { static { // Encodings and suffixes from: https://tools.ietf.org/html/rfc6838 - final Comparator comparator = Comparator.comparing(Function.identity(), String::compareToIgnoreCase); - - SUPPORTED_MIME_TYPES = new TreeMap<>(comparator); + SUPPORTED_MIME_TYPES = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); SUPPORTED_MIME_TYPES.put("text/xml", XML); SUPPORTED_MIME_TYPES.put("application/xml", XML); SUPPORTED_MIME_TYPES.put("application/json", JSON); - SUPPORTED_SUFFIXES = new TreeMap<>(comparator); + SUPPORTED_SUFFIXES = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); SUPPORTED_SUFFIXES.put("xml", XML); SUPPORTED_SUFFIXES.put("json", JSON); } From 3d5d9f163deaa95670653ae1890669dad143044f Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 18 May 2020 14:44:58 -0700 Subject: [PATCH 4/4] Remove unused imports. --- .../java/com/azure/core/util/serializer/SerializerEncoding.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java index 76dfdd956333..287a3a5c8bfe 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/serializer/SerializerEncoding.java @@ -6,10 +6,8 @@ import com.azure.core.http.HttpHeaders; import com.azure.core.util.logging.ClientLogger; -import java.util.Comparator; import java.util.Map; import java.util.TreeMap; -import java.util.function.Function; /** * Supported serialization encoding formats.