From 9d13f9d6cfa070abbcbcd28e0e0ecd9ff6563260 Mon Sep 17 00:00:00 2001 From: Christoph Schubert Date: Fri, 3 Nov 2023 08:08:56 +0100 Subject: [PATCH] Migrate OData header deduplication (#114) Co-authored-by: Johannes Schneider --- .../client/request/ODataRequestGeneric.java | 14 ++++++++ .../request/ODataRequestResultGeneric.java | 2 +- .../ODataRequestResultGenericTest.java | 34 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestGeneric.java b/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestGeneric.java index 0abc6671d..c95b5dfd1 100644 --- a/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestGeneric.java +++ b/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestGeneric.java @@ -161,6 +161,20 @@ public void setHeader( @Nonnull final String key, @Nullable final String value ) headers.put(key, values); } + /** + * Replace a header with multiple values in the OData HTTP request. + * + * @param key + * The header name. + * @param values + * The header values. + * @since 4.27.0 + */ + public void setHeader( @Nonnull final String key, @Nonnull final Collection values ) + { + headers.put(key, new ArrayList<>(values)); + } + /** * Add a header to the OData HTTP request. * diff --git a/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGeneric.java b/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGeneric.java index f7597e41b..9583fe25c 100644 --- a/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGeneric.java +++ b/datamodel/odata-client/src/main/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGeneric.java @@ -713,7 +713,7 @@ public Try tryGetNextPage() request.getProtocol()); // populate headers - request.getHeaders().forEach(( k, values ) -> values.forEach(v -> nextReadRequest.addHeader(k, v))); + request.getHeaders().forEach(nextReadRequest::setHeader); // execute request return Try.of(() -> nextReadRequest.execute(httpClient)); diff --git a/datamodel/odata-client/src/test/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGenericTest.java b/datamodel/odata-client/src/test/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGenericTest.java index d94fb417c..cfc7d79f9 100644 --- a/datamodel/odata-client/src/test/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGenericTest.java +++ b/datamodel/odata-client/src/test/java/com/sap/cloud/sdk/datamodel/odata/client/request/ODataRequestResultGenericTest.java @@ -7,6 +7,7 @@ import static org.apache.http.HttpVersion.HTTP_1_1; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; @@ -15,10 +16,15 @@ import static org.mockito.Mockito.when; import java.net.SocketException; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpResponse; import org.junit.jupiter.api.Test; @@ -132,4 +138,32 @@ public void getHeaderValuesShouldHandleKeyInsensitivity() assertThat(result.getHeaderValues("someOtherKey")).containsExactly("someOtherValue"); assertThat(result.getHeaderValues("SOMEotherKEY")).containsExactly("someOtherValue"); } + + @Test + @SneakyThrows + public void ensureNoRedundantHeadersForPaginatedRequests() + { + final ODataRequestGeneric oDataRequest = + new ODataRequestRead("generic/service/path", "entity(123)", null, ODataProtocol.V4); + + final BasicHttpResponse httpResponse = new BasicHttpResponse(HTTP_1_1, 200, "OK"); + final String json = "{\"value\":[],\"@odata.nextLink\": \"Foo?$count=true&$select=BarID&$skiptoken='ABCD'\"}"; + httpResponse.setEntity(new StringEntity(json)); + + final HttpClient httpClient = mock(HttpClient.class); + when(httpClient.execute(any())).thenReturn(httpResponse); + + final ODataRequestResultGeneric testResult = + new ODataRequestResultGeneric(oDataRequest, httpResponse, httpClient); + + ODataRequestResultGeneric nextResult = testResult.tryGetNextPage().get(); + nextResult = nextResult.tryGetNextPage().get(); + nextResult = nextResult.tryGetNextPage().get(); + nextResult = nextResult.tryGetNextPage().get(); + nextResult = nextResult.tryGetNextPage().get(); + nextResult = nextResult.tryGetNextPage().get(); + + final Map> lastRequestHeaders = nextResult.getODataRequest().getHeaders(); + assertThat(lastRequestHeaders).containsExactly(entry("Accept", Collections.singletonList("application/json"))); + } }