From 60eef2060be743cd822269f0850bbe04f1238d7b Mon Sep 17 00:00:00 2001 From: Roshin Rajan Panackal Date: Mon, 26 Jan 2026 15:47:24 +0100 Subject: [PATCH 1/4] Move all apache related code out --- datamodel/openapi/openapi-core-apache/pom.xml | 94 +++++++ .../openapi/apache/apiclient}/ApiClient.java | 8 +- .../openapi/apache/apiclient}/BaseApi.java | 2 +- .../apiclient}/DefaultApiResponseHandler.java | 6 +- .../openapi/apache/apiclient}/Pair.java | 2 +- .../apache/apiclient/RFC3339DateFormat.java | 58 +++++ .../apache/core/OpenApiRequestException.java | 64 +++++ .../openapi/apache/core}/OpenApiResponse.java | 2 +- .../apache/core}/OpenApiResponseListener.java | 2 +- .../ApacheApiClientResponseHandlingTest.java | 9 +- .../ApacheApiClientViaConstructorTest.java | 5 +- ...piClientExtensionsDeserializationTest.java | 246 ++++++++++++++++++ .../ApiClientFromDestinationTest.java | 69 +++++ .../GenericParameterTest.java | 160 ++++++++++++ .../GenericReturnTypeTest.java | 119 +++++++++ .../genericreturntype/TestApacheApi.java | 13 +- datamodel/openapi/openapi-core/pom.xml | 12 +- .../openapi/core/OpenApiRequestException.java | 18 -- ...piClientExtensionsDeserializationTest.java | 77 ------ .../ApiClientFromDestinationTest.java | 34 --- .../GenericParameterTest.java | 66 +---- .../GenericReturnTypeTest.java | 4 +- datamodel/openapi/pom.xml | 1 + dependency-bundles/modules-bom/pom.xml | 5 + module-inventory.json | 11 + 25 files changed, 853 insertions(+), 234 deletions(-) create mode 100644 datamodel/openapi/openapi-core-apache/pom.xml rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient}/ApiClient.java (98%) rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient}/BaseApi.java (95%) rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient}/DefaultApiResponseHandler.java (97%) rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient}/Pair.java (89%) create mode 100644 datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java create mode 100644 datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiRequestException.java rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core}/OpenApiResponse.java (87%) rename datamodel/openapi/{openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache => openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core}/OpenApiResponseListener.java (87%) rename datamodel/openapi/{openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi => openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache}/apiclient/ApacheApiClientResponseHandlingTest.java (93%) rename datamodel/openapi/{openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi => openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache}/apiclient/ApacheApiClientViaConstructorTest.java (96%) create mode 100644 datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientExtensionsDeserializationTest.java create mode 100644 datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientFromDestinationTest.java create mode 100644 datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericparameter/GenericParameterTest.java create mode 100644 datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/GenericReturnTypeTest.java rename datamodel/openapi/{openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi => openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache}/genericreturntype/TestApacheApi.java (78%) diff --git a/datamodel/openapi/openapi-core-apache/pom.xml b/datamodel/openapi/openapi-core-apache/pom.xml new file mode 100644 index 000000000..d7a5a5ce3 --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + com.sap.cloud.sdk.datamodel + openapi-parent + 5.27.0-SNAPSHOT + + openapi-core-apache + Data Model - OpenAPI Services - Apache Core + Generic OpenAPI API Core Wrapper for Apache client + https://sap.github.io/cloud-sdk/docs/java/getting-started + + SAP SE + https://www.sap.com + + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + SAP + cloudsdk@sap.com + SAP SE + https://www.sap.com + + + + + com.sap.cloud.sdk.cloudplatform + cloudplatform-connectivity + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient5 + + + org.apache.httpcomponents.client5 + httpclient5 + + + org.apache.httpcomponents.core5 + httpcore5 + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.projectlombok + lombok + provided + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.assertj + assertj-core + test + + + org.wiremock + wiremock + test + + + org.junit.jupiter + junit-jupiter-params + test + + + \ No newline at end of file diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/ApiClient.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClient.java similarity index 98% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/ApiClient.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClient.java index 3e955b9f7..9c41962c0 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/ApiClient.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClient.java @@ -10,9 +10,9 @@ * Do not edit the class manually. */ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; -import static com.sap.cloud.sdk.services.openapi.apache.DefaultApiResponseHandler.isJsonMime; +import static com.sap.cloud.sdk.services.openapi.apache.apiclient.DefaultApiResponseHandler.isJsonMime; import static lombok.AccessLevel.PRIVATE; import java.io.File; @@ -60,8 +60,8 @@ import com.google.common.annotations.Beta; import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; -import com.sap.cloud.sdk.services.openapi.apiclient.RFC3339DateFormat; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponseListener; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/BaseApi.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/BaseApi.java similarity index 95% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/BaseApi.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/BaseApi.java index c189867e6..d9bdec66a 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/BaseApi.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/BaseApi.java @@ -10,7 +10,7 @@ * Do not edit the class manually. */ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; import javax.annotation.Nonnull; diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/DefaultApiResponseHandler.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/DefaultApiResponseHandler.java similarity index 97% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/DefaultApiResponseHandler.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/DefaultApiResponseHandler.java index 75019b07a..04fdd31d6 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/DefaultApiResponseHandler.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/DefaultApiResponseHandler.java @@ -10,7 +10,7 @@ * Do not edit the class manually. */ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; import java.io.File; import java.io.IOException; @@ -43,7 +43,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponseListener; import lombok.RequiredArgsConstructor; diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/Pair.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/Pair.java similarity index 89% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/Pair.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/Pair.java index c0acc45b3..51e43aebe 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/Pair.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/Pair.java @@ -10,7 +10,7 @@ * Do not edit the class manually. */ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; import javax.annotation.Nonnull; diff --git a/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java new file mode 100644 index 000000000..4d45d5719 --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java @@ -0,0 +1,58 @@ +package com.sap.cloud.sdk.services.openapi.apache.apiclient; + +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.fasterxml.jackson.databind.util.StdDateFormat; + +/** + * Date format according to the RFC3339. + */ +public class RFC3339DateFormat extends DateFormat +{ + private static final long serialVersionUID = 1L; + private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); + + private final StdDateFormat fmt = new StdDateFormat().withTimeZone(TIMEZONE_Z).withColonInTimeZone(true); + + /** + * Default constructor + */ + public RFC3339DateFormat() + { + calendar = new GregorianCalendar(); + numberFormat = new DecimalFormat(); + } + + @Override + @Nonnull + public Date parse( @Nonnull final String source ) + { + return parse(source, new ParsePosition(0)); + } + + @Override + @Nonnull + public Date parse( @Nonnull final String source, @Nonnull final ParsePosition pos ) + { + return fmt.parse(source, pos); + } + + @Override + @Nonnull + public StringBuffer format( + @Nonnull final Date date, + @Nonnull final StringBuffer toAppendTo, + @Nullable final FieldPosition fieldPosition ) + { + return fmt.format(date, toAppendTo, fieldPosition); + } +} diff --git a/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiRequestException.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiRequestException.java new file mode 100644 index 000000000..6b648f45f --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiRequestException.java @@ -0,0 +1,64 @@ +package com.sap.cloud.sdk.services.openapi.apache.core; + +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + * Thrown if an error occurs during the invocation of a OpenAPI service. + */ +@Accessors( fluent = true ) +@Getter +@Setter +public class OpenApiRequestException extends RuntimeException +{ + private static final long serialVersionUID = -8248392392632616674L; + + @Nullable + private Integer statusCode; + @Nullable + private transient Map> responseHeaders; + @Nullable + private transient String responseBody; + + /** + * Thrown if an error occurs during the invocation of a OpenAPI service. + * + * @param message + * The message of this exception + */ + public OpenApiRequestException( @Nonnull final String message ) + { + super(message); + } + + /** + * Thrown if an error occurs during the invocation of a OpenAPI service. + * + * @param message + * The message of this exception + * @param cause + * The cause of this exception + */ + public OpenApiRequestException( @Nonnull final String message, @Nonnull final Throwable cause ) + { + super(message, cause); + } + + /** + * Thrown if an error occurs during the invocation of a OpenAPI service. + * + * @param cause + * The cause of this exception + */ + public OpenApiRequestException( @Nonnull final Throwable cause ) + { + super(cause); + } +} diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponse.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponse.java similarity index 87% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponse.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponse.java index 900df7887..4fdadc63f 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponse.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponse.java @@ -1,4 +1,4 @@ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.core; import java.util.List; import java.util.Map; diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponseListener.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponseListener.java similarity index 87% rename from datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponseListener.java rename to datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponseListener.java index 36a97303c..e14f17955 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apache/OpenApiResponseListener.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/core/OpenApiResponseListener.java @@ -1,4 +1,4 @@ -package com.sap.cloud.sdk.services.openapi.apache; +package com.sap.cloud.sdk.services.openapi.apache.core; import javax.annotation.Nonnull; diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientResponseHandlingTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientResponseHandlingTest.java similarity index 93% rename from datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientResponseHandlingTest.java rename to datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientResponseHandlingTest.java index 533130569..5c64fdce1 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientResponseHandlingTest.java +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientResponseHandlingTest.java @@ -1,4 +1,4 @@ -package com.sap.cloud.sdk.services.openapi.apiclient; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.get; @@ -20,11 +20,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.Pair; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; import lombok.Data; diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientViaConstructorTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientViaConstructorTest.java similarity index 96% rename from datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientViaConstructorTest.java rename to datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientViaConstructorTest.java index ae2912fd0..eee92c913 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApacheApiClientViaConstructorTest.java +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApacheApiClientViaConstructorTest.java @@ -1,4 +1,4 @@ -package com.sap.cloud.sdk.services.openapi.apiclient; +package com.sap.cloud.sdk.services.openapi.apache.apiclient; import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; @@ -29,9 +29,6 @@ import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5FactoryBuilder; import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5FactoryBuilder.TlsUpgrade; import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; import jdk.jfr.Description; diff --git a/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientExtensionsDeserializationTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientExtensionsDeserializationTest.java new file mode 100644 index 000000000..8aa61b02f --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientExtensionsDeserializationTest.java @@ -0,0 +1,246 @@ +package com.sap.cloud.sdk.services.openapi.apache.apiclient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.entry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.StringJoiner; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; + +import jdk.jfr.Description; +import lombok.Getter; +import lombok.Setter; + +@WireMockTest +class ApiClientExtensionsDeserializationTest +{ + @Nonnull + private static final String BASE_PATH = "http://localhost:8080"; + @Nonnull + private static final String RELATIVE_PATH = "/outer"; + @Nonnull + private static final String RESPONSE = """ + { + "message": "Hello from the outer level.", + "code": 1337, + "inner": { + "message": "Hello from the inner level.", + "code": 7331, + "innerComplexExtension": { + "innerString": "inner", + "innerInteger": 24 + }, + "innerListExtension": [ + "oof", + "rab", + "zab" + ], + "innerPrimitiveExtension": "additionalInnerValue" + }, + "outerComplexExtension": { + "outerString": "outer", + "outerInteger": 42 + }, + "outerListExtension": [ + "foo", + "bar", + "baz" + ], + "outerPrimitiveExtension": "additionalOuterValue" + } + """; + + @Test + @Description( "Tests deserialization of responses with nested extensions using the Apache HTTP client based ApiClient." ) + void testDeserializeResponseWithNestedExtensionsApache( WireMockRuntimeInfo wmInfo ) + { + + WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(RELATIVE_PATH)).willReturn(WireMock.okJson(RESPONSE))); + final var apiClient = ApiClient.create().withBasePath(wmInfo.getHttpBaseUrl()); + + final TestApacheApi api = new TestApacheApi(apiClient); + final Outer result = api.getOuter(); + + WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo(RELATIVE_PATH))); + assertResult(result); + } + + private static void assertResult( Outer result ) + { + assertThat(result.getMessage()).isEqualTo("Hello from the outer level."); + assertThat(result.getCode()).isEqualTo(1337); + assertThat(result.getCustomFieldNames()) + .containsExactlyInAnyOrder("outerComplexExtension", "outerListExtension", "outerPrimitiveExtension"); + assertThat(result.getCustomField("outerPrimitiveExtension")).isEqualTo("additionalOuterValue"); + assertThat(result.getCustomField("outerListExtension")).satisfies(outerList -> { + assertThat(outerList).isInstanceOf(List.class); + assertThat(outerList) + .asInstanceOf(InstanceOfAssertFactories.list(String.class)) + .containsExactlyInAnyOrder("foo", "bar", "baz"); + }); + assertThat(result.getCustomField("outerComplexExtension")).satisfies(outerExtensions -> { + assertThat(outerExtensions).isInstanceOf(Map.class); + assertThat(outerExtensions) + .asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class)) + .containsOnly(entry("outerString", "outer"), entry("outerInteger", 42)); + }); + + assertThat(result.getInner()).satisfies(inner -> { + assertThat(inner.getMessage()).isEqualTo("Hello from the inner level."); + assertThat(inner.getCode()).isEqualTo(7331); + assertThat(inner.getCustomFieldNames()) + .containsExactlyInAnyOrder("innerComplexExtension", "innerListExtension", "innerPrimitiveExtension"); + assertThat(inner.getCustomField("innerPrimitiveExtension")).isEqualTo("additionalInnerValue"); + assertThat(inner.getCustomField("innerListExtension")).satisfies(innerList -> { + assertThat(innerList).isInstanceOf(List.class); + assertThat(innerList) + .asInstanceOf(InstanceOfAssertFactories.list(String.class)) + .containsExactlyInAnyOrder("oof", "rab", "zab"); + }); + assertThat(inner.getCustomField("innerComplexExtension")).satisfies(innerExtensions -> { + assertThat(innerExtensions).isInstanceOf(Map.class); + assertThat(innerExtensions) + .asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class)) + .containsOnly(entry("innerString", "inner"), entry("innerInteger", 24)); + }); + }); + } + + private static class TestApacheApi extends BaseApi + { + public TestApacheApi( final ApiClient apiClient ) + { + super(apiClient); + } + + @Nonnull + public Outer getOuter() + throws OpenApiRequestException + { + final Object localVarPostBody = null; + + // create path and map variables + final String localVarPath = RELATIVE_PATH; + + final StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); + String localVarQueryParameterBaseName; + final List localVarQueryParams = new ArrayList(); + final List localVarCollectionQueryParams = new ArrayList(); + final Map localVarHeaderParams = new HashMap(); + final Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { "application/json" }; + final String localVarAccept = ApiClient.selectHeaderAccept(localVarAccepts); + + final String[] localVarContentTypes = { + + }; + final String localVarContentType = ApiClient.selectHeaderContentType(localVarContentTypes); + + final TypeReference localVarReturnType = new TypeReference() + { + }; + return apiClient + .invokeAPI( + localVarPath, + "GET", + localVarQueryParams, + localVarCollectionQueryParams, + localVarQueryStringJoiner.toString(), + localVarPostBody, + localVarHeaderParams, + localVarFormParams, + localVarAccept, + localVarContentType, + localVarReturnType); + } + } + + private static class Inner + { + @JsonProperty( "message" ) + @Getter + @Setter + private String message; + + @JsonProperty( "code" ) + @Getter + @Setter + private Integer code; + + @JsonAnySetter + private final Map cloudSdkCustomFields = new LinkedHashMap<>(); + + @Nonnull + public Set getCustomFieldNames() + { + return cloudSdkCustomFields.keySet(); + } + + @Nullable + public Object getCustomField( @Nonnull final String name ) + throws NoSuchElementException + { + if( !cloudSdkCustomFields.containsKey(name) ) { + throw new NoSuchElementException("Error has no field with name '" + name + "'."); + } + return cloudSdkCustomFields.get(name); + } + } + + private static class Outer + { + @JsonProperty( "message" ) + @Getter + @Setter + private String message; + + @JsonProperty( "code" ) + @Getter + @Setter + private Integer code; + + @JsonProperty( "inner" ) + @Getter + @Setter + private Inner inner; + + @JsonAnySetter + private final Map cloudSdkCustomFields = new LinkedHashMap<>(); + + @Nonnull + public Set getCustomFieldNames() + { + return cloudSdkCustomFields.keySet(); + } + + @Nullable + public Object getCustomField( @Nonnull final String name ) + throws NoSuchElementException + { + if( !cloudSdkCustomFields.containsKey(name) ) { + throw new NoSuchElementException("Error has no field with name '" + name + "'."); + } + return cloudSdkCustomFields.get(name); + } + } +} diff --git a/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientFromDestinationTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientFromDestinationTest.java new file mode 100644 index 000000000..cc60b087c --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/ApiClientFromDestinationTest.java @@ -0,0 +1,69 @@ +package com.sap.cloud.sdk.services.openapi.apache.apiclient; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; +import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; +import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; + +class ApiClientFromDestinationTest +{ + @RegisterExtension + static final WireMockExtension SERVER = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @Test + void testServiceInvocation() + { + final HttpDestination testDestination = DefaultHttpDestination.builder(SERVER.baseUrl()).build(); + + final MyTestAbstractApacheOpenApiService apacheService = + new MyTestAbstractApacheOpenApiService(testDestination); + + apacheService.foo(); + } + + @Test + void testExceptionIsThrown() + { + final HttpDestination testDestination = DefaultHttpDestination.builder(SERVER.baseUrl()).build(); + + final MyExceptionThrowingApacheServiceAbstract apacheService = + new MyExceptionThrowingApacheServiceAbstract(testDestination); + + assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(apacheService::foo); + } + + private static class MyTestAbstractApacheOpenApiService extends BaseApi + { + public MyTestAbstractApacheOpenApiService( final Destination destination ) + { + super(destination); + } + + void foo() + { + assertThat(apiClient.getBasePath()).isEqualTo(SERVER.baseUrl()); + } + } + + private static class MyExceptionThrowingApacheServiceAbstract extends BaseApi + { + public MyExceptionThrowingApacheServiceAbstract( final Destination destination ) + { + super(destination); + } + + void foo() + throws IllegalAccessException + { + throw new IllegalAccessException("Something went horribly wrong"); + } + } +} diff --git a/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericparameter/GenericParameterTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericparameter/GenericParameterTest.java new file mode 100644 index 000000000..1bb09bf1a --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericparameter/GenericParameterTest.java @@ -0,0 +1,160 @@ +package com.sap.cloud.sdk.services.openapi.apache.genericparameter; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.hc.core5.http.HttpStatus; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRawValue; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; +import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; + +import lombok.Builder; +import lombok.Value; + +@WireMockTest +class GenericParameterTest +{ + final static String EXPECTED_BODY = """ + {\ + "id":"foo",\ + "fieldPopulatedAsStringWithAnnotation":{"foo": "bar"},\ + "fieldPopulatedAsStringWithoutAnnotation":"{\\"foo\\": \\"bar\\"}",\ + "fieldPopulatedAsJacksonJsonNode":{"foo":"bar"}\ + }\ + """; + + @Test + void testInvocationWithGenericParameter( @Nonnull final WireMockRuntimeInfo wm ) + throws JsonProcessingException + { + + WireMock + .stubFor( + post(urlEqualTo("/api")) + .withRequestBody(equalTo(EXPECTED_BODY)) + .willReturn(aResponse().withStatus(HttpStatus.SC_OK))); + + final DefaultHttpDestination httpDestination = DefaultHttpDestination.builder(wm.getHttpBaseUrl()).build(); + + final String jsonString = "{\"foo\": \"bar\"}"; + + //this is how you pass a JSON representation into a parameter of type Object + final JsonNode jacksonJsonNode = new ObjectMapper().readTree(jsonString); + + final TestModelPOST testModelPOST = + TestModelPOST + .builder() + .id("foo") + .fieldPopulatedAsStringWithAnnotation(jsonString) + .fieldPopulatedAsStringWithoutAnnotation(jsonString) + .fieldPopulatedAsJacksonJsonNode(jacksonJsonNode) + .build(); + + new TestApacheApi(httpDestination).testMethod(testModelPOST); + verify(1, postRequestedFor(urlEqualTo("/api")).withRequestBody(equalTo(EXPECTED_BODY))); + } + + @Value + @Builder + private static class TestModelPOST + { + @JsonProperty( "id" ) + String id; + + @JsonProperty( "fieldPopulatedAsStringWithAnnotation" ) + @JsonRawValue + Object fieldPopulatedAsStringWithAnnotation; + + @JsonProperty( "fieldPopulatedAsStringWithoutAnnotation" ) + Object fieldPopulatedAsStringWithoutAnnotation; + + @JsonProperty( "fieldPopulatedAsJacksonJsonNode" ) + Object fieldPopulatedAsJacksonJsonNode; + } + + private static class TestApacheApi extends BaseApi + { + public TestApacheApi( @Nonnull final Destination destination ) + { + super(destination); + } + + @Nullable + public TestModel testMethod( @Nonnull final TestModelPOST body ) + throws OpenApiRequestException + { + final Object localVarPostBody = body; + + // verify the required parameter 'pet' is set + if( body == null ) { + throw new OpenApiRequestException("Missing the required parameter 'pet' when calling addPet") + .statusCode(400); + } + + // create path and map variables + final String localVarPath = "/api"; + + final StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); + String localVarQueryParameterBaseName; + final List localVarQueryParams = new ArrayList(); + final List localVarCollectionQueryParams = new ArrayList(); + final Map localVarHeaderParams = new HashMap(); + final Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { "application/json" }; + final String localVarAccept = ApiClient.selectHeaderAccept(localVarAccepts); + + final String[] localVarContentTypes = { "application/json" }; + final String localVarContentType = ApiClient.selectHeaderContentType(localVarContentTypes); + + final TypeReference localVarReturnType = new TypeReference() + { + }; + return apiClient + .invokeAPI( + localVarPath, + "POST", + localVarQueryParams, + localVarCollectionQueryParams, + localVarQueryStringJoiner.toString(), + localVarPostBody, + localVarHeaderParams, + localVarFormParams, + localVarAccept, + localVarContentType, + localVarReturnType); + } + + } + + private static class TestModel + { + } +} diff --git a/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/GenericReturnTypeTest.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/GenericReturnTypeTest.java new file mode 100644 index 000000000..5db758aa2 --- /dev/null +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/GenericReturnTypeTest.java @@ -0,0 +1,119 @@ +package com.sap.cloud.sdk.services.openapi.apache.genericreturntype; + +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Stream; + +import javax.annotation.Nonnull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; +import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; + +/** + * This test covers an edge case of API endpoints whose response is configured as follows: + * + * // @formatter:off + * responses: + * '200': + * description: Returns the context of the specified user task. + * schema: + * type: object + * description: The context of the user task. + * examples: + * application/json: + * firstname: John + * lastname: Doe + * // @formatter:on + * + * More specifically, the edge case is that the response body schema is not specified. We only know that it represents a generic response + * object + * + * This test case demonstrates that the returned Java type at runtime is a {@link LinkedHashMap}. + */ +@WireMockTest +class GenericReturnTypeTest +{ + + HttpDestination httpDestination; + + @BeforeEach + void setUp( @Nonnull final WireMockRuntimeInfo wm ) + { + httpDestination = DefaultHttpDestination.builder(wm.getHttpBaseUrl()).build(); + } + + static Stream provideContext() + { + return Stream + .of(Arguments.of((Function) ( des ) -> new TestApacheApi(des).testMethod())); + } + + @MethodSource( "provideContext" ) + @ParameterizedTest + void testGenericAccessToNonNestedJsonObject( @Nonnull final Function contextFactory ) + { + final String responseBody = "{\"firstname\":\"John\",\"lastname\":\"Doe\"}"; + stubFor(get(urlEqualTo("/endpoint")).willReturn(okJson(responseBody))); + + final Object context = contextFactory.apply(httpDestination); + + @SuppressWarnings( "unchecked" ) + final LinkedHashMap castedReturnObject = (LinkedHashMap) context; + + assertThat(castedReturnObject.get("firstname")).isEqualTo("John"); + assertThat(castedReturnObject.get("lastname")).isEqualTo("Doe"); + } + + @MethodSource( "provideContext" ) + @ParameterizedTest + void testGenericAccessToNestedJsonObject( @Nonnull final Function contextFactory ) + { + final String responseBody = "{" + "\"foo\": \"bar\"," + "\"bar\": {" + "\"foobar\": \"barfoo\"" + "}" + "}"; + + stubFor(get(urlEqualTo("/endpoint")).willReturn(okJson(responseBody))); + + final Object context = contextFactory.apply(httpDestination); + + @SuppressWarnings( "unchecked" ) + final LinkedHashMap castedReturnObject = (LinkedHashMap) context; + + assertThat(castedReturnObject.get("foo")).isEqualTo("bar"); + + @SuppressWarnings( "unchecked" ) + final LinkedHashMap castedNestedReturnObject = + (LinkedHashMap) castedReturnObject.get("bar"); + + assertThat(castedNestedReturnObject.get("foobar")).isEqualTo("barfoo"); + } + + @MethodSource( "provideContext" ) + @ParameterizedTest + void testGenericAccessToArray( @Nonnull final Function contextFactory ) + { + final String responseBody = "[\"foo\", \"bar\", \"foo\", \"bar\"]"; + + stubFor(get(urlEqualTo("/endpoint")).willReturn(okJson(responseBody))); + + final Object context = contextFactory.apply(httpDestination); + + @SuppressWarnings( "unchecked" ) + final List castedReturnObject = (List) context; + + assertThat(castedReturnObject).hasSize(4); + assertThat(castedReturnObject).containsExactly("foo", "bar", "foo", "bar"); + } +} diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/TestApacheApi.java b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/TestApacheApi.java similarity index 78% rename from datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/TestApacheApi.java rename to datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/TestApacheApi.java index 6e3f10aca..320b980d2 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/TestApacheApi.java +++ b/datamodel/openapi/openapi-core-apache/src/test/java/com/sap/cloud/sdk/services/openapi/apache/genericreturntype/TestApacheApi.java @@ -1,4 +1,4 @@ -package com.sap.cloud.sdk.services.openapi.genericreturntype; +package com.sap.cloud.sdk.services.openapi.apache.genericreturntype; import java.util.ArrayList; import java.util.HashMap; @@ -10,8 +10,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; class TestApacheApi extends BaseApi { @@ -36,14 +37,12 @@ Object testMethod() final Map localVarFormParams = new HashMap(); final String[] localVarAccepts = { "application/json" }; - final String localVarAccept = - com.sap.cloud.sdk.services.openapi.apache.ApiClient.selectHeaderAccept(localVarAccepts); + final String localVarAccept = ApiClient.selectHeaderAccept(localVarAccepts); final String[] localVarContentTypes = { }; - final String localVarContentType = - com.sap.cloud.sdk.services.openapi.apache.ApiClient.selectHeaderContentType(localVarContentTypes); + final String localVarContentType = ApiClient.selectHeaderContentType(localVarContentTypes); final TypeReference localVarReturnType = new TypeReference() { diff --git a/datamodel/openapi/openapi-core/pom.xml b/datamodel/openapi/openapi-core/pom.xml index 7d6e2d422..42fdbc2bd 100644 --- a/datamodel/openapi/openapi-core/pom.xml +++ b/datamodel/openapi/openapi-core/pom.xml @@ -68,10 +68,6 @@ com.fasterxml.jackson.core jackson-core - - com.google.guava - guava - org.projectlombok @@ -102,13 +98,9 @@ org.apache.httpcomponents.core5 httpcore5 - - - org.junit.jupiter - junit-jupiter-params test - - + + diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiRequestException.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiRequestException.java index 6237641e1..c22e6a505 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiRequestException.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiRequestException.java @@ -1,32 +1,14 @@ package com.sap.cloud.sdk.services.openapi.core; -import java.util.List; -import java.util.Map; - import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; /** * Thrown if an error occurs during the invocation of a OpenAPI service. */ -@Accessors( fluent = true ) -@Getter -@Setter public class OpenApiRequestException extends RuntimeException { private static final long serialVersionUID = -8248392392632616674L; - @Nullable - private Integer statusCode; - @Nullable - private transient Map> responseHeaders; - @Nullable - private transient String responseBody; - /** * Thrown if an error occurs during the invocation of a OpenAPI service. * diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientExtensionsDeserializationTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientExtensionsDeserializationTest.java index e4e27e010..31e829785 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientExtensionsDeserializationTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientExtensionsDeserializationTest.java @@ -5,14 +5,12 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import java.util.StringJoiner; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -33,16 +31,9 @@ import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.type.TypeReference; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; import com.sap.cloud.sdk.services.openapi.core.AbstractOpenApiService; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import jdk.jfr.Description; import lombok.Getter; import lombok.Setter; @@ -104,22 +95,6 @@ void testDeserializeResponseWithNestedExtensions() assertResult(result); } - @Test - @Description( "Tests deserialization of responses with nested extensions using the Apache HTTP client based ApiClient." ) - void testDeserializeResponseWithNestedExtensionsApache( WireMockRuntimeInfo wmInfo ) - { - - WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(RELATIVE_PATH)).willReturn(WireMock.okJson(RESPONSE))); - final var apiClient = - com.sap.cloud.sdk.services.openapi.apache.ApiClient.create().withBasePath(wmInfo.getHttpBaseUrl()); - - final TestApacheApi api = new TestApacheApi(apiClient); - final Outer result = api.getOuter(); - - WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo(RELATIVE_PATH))); - assertResult(result); - } - private static void assertResult( Outer result ) { assertThat(result.getMessage()).isEqualTo("Hello from the outer level."); @@ -161,58 +136,6 @@ private static void assertResult( Outer result ) }); } - private static class TestApacheApi extends BaseApi - { - public TestApacheApi( final com.sap.cloud.sdk.services.openapi.apache.ApiClient apiClient ) - { - super(apiClient); - } - - @Nonnull - public Outer getOuter() - throws OpenApiRequestException - { - final Object localVarPostBody = null; - - // create path and map variables - final String localVarPath = RELATIVE_PATH; - - final StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); - String localVarQueryParameterBaseName; - final List localVarQueryParams = new ArrayList(); - final List localVarCollectionQueryParams = new ArrayList(); - final Map localVarHeaderParams = new HashMap(); - final Map localVarFormParams = new HashMap(); - - final String[] localVarAccepts = { "application/json" }; - final String localVarAccept = - com.sap.cloud.sdk.services.openapi.apache.ApiClient.selectHeaderAccept(localVarAccepts); - - final String[] localVarContentTypes = { - - }; - final String localVarContentType = - com.sap.cloud.sdk.services.openapi.apache.ApiClient.selectHeaderContentType(localVarContentTypes); - - final TypeReference localVarReturnType = new TypeReference() - { - }; - return apiClient - .invokeAPI( - localVarPath, - "GET", - localVarQueryParams, - localVarCollectionQueryParams, - localVarQueryStringJoiner.toString(), - localVarPostBody, - localVarHeaderParams, - localVarFormParams, - localVarAccept, - localVarContentType, - localVarReturnType); - } - } - private static class TestSpringApi extends AbstractOpenApiService { public TestSpringApi( final ApiClient apiClient ) diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientFromDestinationTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientFromDestinationTest.java index 8135e9c6e..1fbd7854b 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientFromDestinationTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientFromDestinationTest.java @@ -11,7 +11,6 @@ import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; import com.sap.cloud.sdk.services.openapi.core.AbstractOpenApiService; class ApiClientFromDestinationTest @@ -26,11 +25,8 @@ void testServiceInvocation() final HttpDestination testDestination = DefaultHttpDestination.builder(SERVER.baseUrl()).build(); final MyTestAbstractOpenApiService springService = new MyTestAbstractOpenApiService(testDestination); - final MyTestAbstractApacheOpenApiService apacheService = - new MyTestAbstractApacheOpenApiService(testDestination); springService.foo(); - apacheService.foo(); } @Test @@ -40,11 +36,8 @@ void testExceptionIsThrown() final MyExceptionThrowingSpringServiceAbstract springService = new MyExceptionThrowingSpringServiceAbstract(testDestination); - final MyExceptionThrowingApacheServiceAbstract apacheService = - new MyExceptionThrowingApacheServiceAbstract(testDestination); assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(springService::foo); - assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(apacheService::foo); } private static class MyTestAbstractOpenApiService extends AbstractOpenApiService @@ -73,31 +66,4 @@ void foo() throw new IllegalAccessException("Something went horribly wrong"); } } - - private static class MyTestAbstractApacheOpenApiService extends BaseApi - { - public MyTestAbstractApacheOpenApiService( final Destination destination ) - { - super(destination); - } - - void foo() - { - assertThat(apiClient.getBasePath()).isEqualTo(SERVER.baseUrl()); - } - } - - private static class MyExceptionThrowingApacheServiceAbstract extends BaseApi - { - public MyExceptionThrowingApacheServiceAbstract( final Destination destination ) - { - super(destination); - } - - void foo() - throws IllegalAccessException - { - throw new IllegalAccessException("Something went horribly wrong"); - } - } } diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java index 035effa39..9e18ec4b3 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java @@ -7,11 +7,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.StringJoiner; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -29,7 +25,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRawValue; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.client.WireMock; @@ -37,9 +32,6 @@ import com.github.tomakehurst.wiremock.junit5.WireMockTest; import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; import com.sap.cloud.sdk.services.openapi.core.AbstractOpenApiService; import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; @@ -86,8 +78,7 @@ void testInvocationWithGenericParameter( @Nonnull final WireMockRuntimeInfo wm ) .build(); new TestSpringApi(httpDestination).testMethod(testModelPOST); - new TestApacheApi(httpDestination).testMethod(testModelPOST); - verify(2, postRequestedFor(urlEqualTo("/api")).withRequestBody(equalTo(EXPECTED_BODY))); + verify(1, postRequestedFor(urlEqualTo("/api")).withRequestBody(equalTo(EXPECTED_BODY))); } @Value @@ -108,61 +99,6 @@ private static class TestModelPOST Object fieldPopulatedAsJacksonJsonNode; } - private static class TestApacheApi extends BaseApi - { - public TestApacheApi( @Nonnull final Destination destination ) - { - super(destination); - } - - @Nullable - public TestModel testMethod( @Nonnull final TestModelPOST body ) - throws OpenApiRequestException - { - final Object localVarPostBody = body; - - // verify the required parameter 'pet' is set - if( body == null ) { - throw new OpenApiRequestException("Missing the required parameter 'pet' when calling addPet") - .statusCode(400); - } - - // create path and map variables - final String localVarPath = "/api"; - - final StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); - String localVarQueryParameterBaseName; - final List localVarQueryParams = new ArrayList(); - final List localVarCollectionQueryParams = new ArrayList(); - final Map localVarHeaderParams = new HashMap(); - final Map localVarFormParams = new HashMap(); - - final String[] localVarAccepts = { "application/json" }; - final String localVarAccept = ApiClient.selectHeaderAccept(localVarAccepts); - - final String[] localVarContentTypes = { "application/json" }; - final String localVarContentType = ApiClient.selectHeaderContentType(localVarContentTypes); - - final TypeReference localVarReturnType = new TypeReference() - { - }; - return apiClient - .invokeAPI( - localVarPath, - "POST", - localVarQueryParams, - localVarCollectionQueryParams, - localVarQueryStringJoiner.toString(), - localVarPostBody, - localVarHeaderParams, - localVarFormParams, - localVarAccept, - localVarContentType, - localVarReturnType); - } - - } - private static class TestSpringApi extends AbstractOpenApiService { public TestSpringApi( @Nonnull final Destination httpDestination ) diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/GenericReturnTypeTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/GenericReturnTypeTest.java index 4d909438b..f76013f28 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/GenericReturnTypeTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericreturntype/GenericReturnTypeTest.java @@ -59,9 +59,7 @@ void setUp( @Nonnull final WireMockRuntimeInfo wm ) static Stream provideContext() { return Stream - .of( - Arguments.of((Function) ( des ) -> new TestSpringApi(des).testMethod()), - Arguments.of((Function) ( des ) -> new TestApacheApi(des).testMethod())); + .of(Arguments.of((Function) ( des ) -> new TestSpringApi(des).testMethod())); } @MethodSource( "provideContext" ) diff --git a/datamodel/openapi/pom.xml b/datamodel/openapi/pom.xml index 65cd0a8f1..c446f1dae 100644 --- a/datamodel/openapi/pom.xml +++ b/datamodel/openapi/pom.xml @@ -31,6 +31,7 @@ openapi-core + openapi-core-apache openapi-generator openapi-generator-maven-plugin openapi-api-sample diff --git a/dependency-bundles/modules-bom/pom.xml b/dependency-bundles/modules-bom/pom.xml index 926a4f6ba..5a4d5bb94 100644 --- a/dependency-bundles/modules-bom/pom.xml +++ b/dependency-bundles/modules-bom/pom.xml @@ -198,6 +198,11 @@ openapi-core ${sdk.version} + + com.sap.cloud.sdk.datamodel + openapi-core-apache + ${sdk.version} + com.sap.cloud.sdk.datamodel openapi-generator diff --git a/module-inventory.json b/module-inventory.json index 03840ca6e..71f993b18 100644 --- a/module-inventory.json +++ b/module-inventory.json @@ -428,6 +428,17 @@ "parentArtifactId": "openapi-parent", "excludeFromBlackDuckScan": false }, + { + "groupId": "com.sap.cloud.sdk.datamodel", + "artifactId": "openapi-core-apache", + "packaging": "jar", + "releaseAudience": "Public", + "releaseMaturity": "Stable", + "pomFile": "datamodel/openapi/openapi-core-apache/pom.xml", + "parentGroupId": "com.sap.cloud.sdk.datamodel", + "parentArtifactId": "openapi-parent", + "excludeFromBlackDuckScan": false + }, { "groupId": "com.sap.cloud.sdk.datamodel", "artifactId": "openapi-generator", From 2714513d020c3ee9fbdde57ef23ce8f9beb1525d Mon Sep 17 00:00:00 2001 From: Roshin Rajan Panackal Date: Mon, 26 Jan 2026 16:23:06 +0100 Subject: [PATCH 2/4] Update generator templates and sample module --- datamodel/openapi/openapi-api-apache-sample/pom.xml | 2 +- .../openapi/apache/petstore/api/DefaultApi.java | 10 +++++----- .../openapi/apache/sodastore/api/OrdersApi.java | 8 ++++---- .../openapi/apache/sodastore/api/SodasApi.java | 8 ++++---- datamodel/openapi/openapi-core-apache/pom.xml | 4 ++++ datamodel/openapi/openapi-core/pom.xml | 7 ++++++- .../libraries/apache-httpclient/api.mustache | 10 +++++----- .../cloud/sdk/services/builder/api/AwesomeSodaApi.java | 10 +++++----- .../sdk/services/builder/api/AwesomeSodasApi.java | 10 +++++----- .../sap/cloud/sdk/services/builder/api/DefaultApi.java | 10 +++++----- .../apiclassvendorextension/api/AwesomeSodaApi.java | 10 +++++----- .../apiclassvendorextension/api/AwesomeSodasApi.java | 10 +++++----- .../apiclassvendorextension/api/DefaultApi.java | 10 +++++----- .../apiclassvendorextension/api/DefaultApi.java | 10 +++++----- .../sdk/services/inlineobject/api/DefaultApi.java | 10 +++++----- .../sap/cloud/sdk/services/builder/api/DefaultApi.java | 10 +++++----- .../sap/cloud/sdk/services/builder/api/OrdersApi.java | 10 +++++----- .../sap/cloud/sdk/services/builder/api/SodasApi.java | 10 +++++----- 18 files changed, 84 insertions(+), 75 deletions(-) diff --git a/datamodel/openapi/openapi-api-apache-sample/pom.xml b/datamodel/openapi/openapi-api-apache-sample/pom.xml index 6e9cff770..1f8d5d0dd 100644 --- a/datamodel/openapi/openapi-api-apache-sample/pom.xml +++ b/datamodel/openapi/openapi-api-apache-sample/pom.xml @@ -31,7 +31,7 @@ com.sap.cloud.sdk.datamodel - openapi-core + openapi-core-apache com.sap.cloud.sdk.cloudplatform diff --git a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/petstore/api/DefaultApi.java b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/petstore/api/DefaultApi.java index b08117f8d..9b7f9bad7 100644 --- a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/petstore/api/DefaultApi.java +++ b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/petstore/api/DefaultApi.java @@ -17,11 +17,11 @@ import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; import com.sap.cloud.sdk.datamodel.openapi.apache.petstore.model.Pet; import com.sap.cloud.sdk.datamodel.openapi.apache.petstore.model.PetInput; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.Pair; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; /** * Swagger Petstore in version 1.0.0. diff --git a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/OrdersApi.java b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/OrdersApi.java index c6d82a1d8..47c99e6ab 100644 --- a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/OrdersApi.java +++ b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/OrdersApi.java @@ -15,10 +15,10 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; import com.sap.cloud.sdk.datamodel.openapi.apache.sodastore.model.Order; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; /** * SodaStore API in version 1.0.0. diff --git a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/SodasApi.java b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/SodasApi.java index 8e3f539f4..f736f96fd 100644 --- a/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/SodasApi.java +++ b/datamodel/openapi/openapi-api-apache-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/apache/sodastore/api/SodasApi.java @@ -17,10 +17,10 @@ import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; import com.sap.cloud.sdk.datamodel.openapi.apache.sodastore.model.Soda; import com.sap.cloud.sdk.datamodel.openapi.apache.sodastore.model.SodaWithId; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; /** * SodaStore API in version 1.0.0. diff --git a/datamodel/openapi/openapi-core-apache/pom.xml b/datamodel/openapi/openapi-core-apache/pom.xml index d7a5a5ce3..da363410d 100644 --- a/datamodel/openapi/openapi-core-apache/pom.xml +++ b/datamodel/openapi/openapi-core-apache/pom.xml @@ -63,6 +63,10 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + + com.google.guava + guava + org.projectlombok diff --git a/datamodel/openapi/openapi-core/pom.xml b/datamodel/openapi/openapi-core/pom.xml index 42fdbc2bd..bafa23b0a 100644 --- a/datamodel/openapi/openapi-core/pom.xml +++ b/datamodel/openapi/openapi-core/pom.xml @@ -100,7 +100,12 @@ httpcore5 test - + + org.junit.jupiter + junit-jupiter-params + test + + diff --git a/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/libraries/apache-httpclient/api.mustache b/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/libraries/apache-httpclient/api.mustache index b14178041..bf3dc226d 100644 --- a/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/libraries/apache-httpclient/api.mustache +++ b/datamodel/openapi/openapi-generator/src/main/resources/openapi-generator/mustache-templates/libraries/apache-httpclient/api.mustache @@ -8,11 +8,11 @@ package {{package}}; import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; {{#models.0}} import {{modelPackage}}.*; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodaApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodaApi.java index 81edc6ad9..2feef4ee1 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodaApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodaApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.NewSoda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodasApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodasApi.java index 946607d7a..5f33c5144 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodasApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/AwesomeSodasApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.Soda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java index d909f2d6c..b47b94f4c 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-for-ai-sdk/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.Soda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodaApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodaApi.java index 6a9d9bc0e..6eb680136 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodaApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodaApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.apiclassvendorextension.model.NewSoda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodasApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodasApi.java index e8bb7f6f6..73aada075 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodasApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/AwesomeSodasApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.apiclassvendorextension.model.Soda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java index b236fece8..52381685b 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-json/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.apiclassvendorextension.model.Soda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-yaml/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-yaml/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java index 97d57f4da..a2c99f75b 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-yaml/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/api-class-vendor-extension-yaml/output/com/sap/cloud/sdk/services/apiclassvendorextension/api/DefaultApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.apiclassvendorextension.model.NewSoda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/inlineobject-schemas-enabled/output/com/sap/cloud/sdk/services/inlineobject/api/DefaultApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/inlineobject-schemas-enabled/output/com/sap/cloud/sdk/services/inlineobject/api/DefaultApi.java index 5614166e3..ecb57428a 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/inlineobject-schemas-enabled/output/com/sap/cloud/sdk/services/inlineobject/api/DefaultApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/inlineobject-schemas-enabled/output/com/sap/cloud/sdk/services/inlineobject/api/DefaultApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.inlineobject.model.NotFound; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/partial-generation/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/partial-generation/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java index 54305d7fe..ae417b114 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/partial-generation/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/partial-generation/output/com/sap/cloud/sdk/services/builder/api/DefaultApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.Soda; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/OrdersApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/OrdersApi.java index 8e5c18589..51b4453fb 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/OrdersApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/OrdersApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.Order; diff --git a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/SodasApi.java b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/SodasApi.java index 1b83674b8..2abf5c1c9 100644 --- a/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/SodasApi.java +++ b/datamodel/openapi/openapi-generator/src/test/resources/DataModelGeneratorApacheIntegrationTest/remove-operation-id-prefix/output/com/sap/cloud/sdk/services/builder/api/SodasApi.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; -import com.sap.cloud.sdk.services.openapi.core.OpenApiRequestException; -import com.sap.cloud.sdk.services.openapi.apache.OpenApiResponse; -import com.sap.cloud.sdk.services.openapi.apache.ApiClient; -import com.sap.cloud.sdk.services.openapi.apache.BaseApi; -import com.sap.cloud.sdk.services.openapi.apache.Pair; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiRequestException; +import com.sap.cloud.sdk.services.openapi.apache.core.OpenApiResponse; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.BaseApi; +import com.sap.cloud.sdk.services.openapi.apache.apiclient.Pair; import com.sap.cloud.sdk.services.builder.model.Soda; From dce8b2fd104905bb08c2b1408b27e14f9f872443 Mon Sep 17 00:00:00 2001 From: Roshin Rajan Panackal Date: Tue, 27 Jan 2026 10:48:05 +0100 Subject: [PATCH 3/4] Update release notes --- release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release_notes.md b/release_notes.md index 3112514a9..9783474c0 100644 --- a/release_notes.md +++ b/release_notes.md @@ -12,7 +12,7 @@ ### ✨ New Functionality -- +- [OpenAPI] Cloud SDK OpenAPI Generator now supports `apache-httpclient` library besides Spring RestTemplate through the newly introduced module `openapi-core-apache`. ### 📈 Improvements From cd2d21bc8a1e92ce3da0a9adbe351763f1d89d2d Mon Sep 17 00:00:00 2001 From: Roshin Rajan Panackal Date: Tue, 27 Jan 2026 13:43:41 +0100 Subject: [PATCH 4/4] Make RFC class package private --- .../services/openapi/apache/apiclient/RFC3339DateFormat.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java index 4d45d5719..2e4c6fa45 100644 --- a/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java +++ b/datamodel/openapi/openapi-core-apache/src/main/java/com/sap/cloud/sdk/services/openapi/apache/apiclient/RFC3339DateFormat.java @@ -16,7 +16,7 @@ /** * Date format according to the RFC3339. */ -public class RFC3339DateFormat extends DateFormat +class RFC3339DateFormat extends DateFormat { private static final long serialVersionUID = 1L; private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); @@ -26,7 +26,7 @@ public class RFC3339DateFormat extends DateFormat /** * Default constructor */ - public RFC3339DateFormat() + RFC3339DateFormat() { calendar = new GregorianCalendar(); numberFormat = new DecimalFormat();