create
diff --git a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/SodasApi.java b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/SodasApi.java
index a512ff249..c06633a74 100644
--- a/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/SodasApi.java
+++ b/datamodel/openapi/openapi-api-sample/src/main/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/SodasApi.java
@@ -57,6 +57,68 @@ public SodasApi( @Nonnull final ApiClient apiClient )
super(apiClient);
}
+ /**
+ *
+ * Download soda product data as binary
+ *
+ *
+ *
+ *
+ * 200 - Successful response
+ *
+ * 404 - Soda product not found
+ *
+ * @param id
+ * ID of the soda product to download
+ * @return byte[]
+ * @throws OpenApiRequestException
+ * if an error occurs while attempting to invoke the API
+ */
+ @Nonnull
+ public byte[] sodasDownloadIdGet( @Nonnull final Long id )
+ throws OpenApiRequestException
+ {
+ final Object localVarPostBody = null;
+
+ // verify the required parameter 'id' is set
+ if( id == null ) {
+ throw new OpenApiRequestException("Missing the required parameter 'id' when calling sodasDownloadIdGet");
+ }
+
+ // create path and map variables
+ final Map localVarPathParams = new HashMap();
+ localVarPathParams.put("id", id);
+ final String localVarPath =
+ UriComponentsBuilder.fromPath("/sodas/download/{id}").buildAndExpand(localVarPathParams).toUriString();
+
+ final MultiValueMap localVarQueryParams = new LinkedMultiValueMap();
+ final HttpHeaders localVarHeaderParams = new HttpHeaders();
+ final MultiValueMap localVarFormParams = new LinkedMultiValueMap();
+
+ final String[] localVarAccepts = { "application/octet-stream" };
+ final List localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
+ final String[] localVarContentTypes = {};
+ final MediaType localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes);
+
+ final String[] localVarAuthNames = new String[] { "apiKeyAuth", "bearerAuth" };
+
+ final ParameterizedTypeReference localVarReturnType = new ParameterizedTypeReference()
+ {
+ };
+ return apiClient
+ .invokeAPI(
+ localVarPath,
+ HttpMethod.GET,
+ localVarQueryParams,
+ localVarPostBody,
+ localVarHeaderParams,
+ localVarFormParams,
+ localVarAccept,
+ localVarContentType,
+ localVarAuthNames,
+ localVarReturnType);
+ }
+
/**
*
* Get all soda products
diff --git a/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml b/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml
index 1fa8ce09a..bf2b80a7f 100644
--- a/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml
+++ b/datamodel/openapi/openapi-api-sample/src/main/resources/sodastore.yaml
@@ -258,6 +258,29 @@ paths:
$ref: '#/components/schemas/SodaWithId'
'404':
description: Soda product not found
+ /sodas/download/{id}:
+ get:
+ summary: Download soda product data as binary
+ tags:
+ - Sodas
+ parameters:
+ - name: id
+ in: path
+ description: ID of the soda product to download
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ '404':
+ description: Soda product not found
/orders:
post:
summary: Create a new order
diff --git a/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/DeserializationTest.java b/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/DeserializationTest.java
index db7e50500..dfe1c7744 100644
--- a/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/DeserializationTest.java
+++ b/datamodel/openapi/openapi-api-sample/src/test/java/com/sap/cloud/sdk/datamodel/openapi/sample/api/DeserializationTest.java
@@ -115,6 +115,26 @@ void testUnexpectedAdditionalField()
assertThat(actual.getCustomField("unexpectedField")).asInstanceOf(InstanceOfAssertFactories.LIST).isEmpty();
}
+ @Test
+ void testBinaryResponse()
+ {
+ final byte[] binaryData = "binary file content".getBytes();
+ WireMock
+ .stubFor(
+ WireMock
+ .get(WireMock.urlMatching("/sodas/download/\\d+"))
+ .willReturn(
+ WireMock
+ .aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/octet-stream")
+ .withBody(binaryData)));
+
+ final byte[] result = sut.sodasDownloadIdGet(1L);
+ assertThat(result).isNotNull();
+ assertThat(result).isEqualTo(binaryData);
+ }
+
private void stub( String responseBody )
{
WireMock.stubFor(WireMock.get(WireMock.anyUrl()).willReturn(okJson(responseBody)));
diff --git a/datamodel/openapi/openapi-generator-maven-plugin/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojo.java b/datamodel/openapi/openapi-generator-maven-plugin/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojo.java
index 7cde3a40f..d5ad79e03 100644
--- a/datamodel/openapi/openapi-generator-maven-plugin/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojo.java
+++ b/datamodel/openapi/openapi-generator-maven-plugin/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojo.java
@@ -1,7 +1,12 @@
package com.sap.cloud.sdk.datamodel.openapi.generator;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -126,6 +131,18 @@ public class DataModelGeneratorMojo extends AbstractMojo
@Parameter( property = "openapi.generate.generateApis", defaultValue = "true" )
private boolean generateApis;
+ /**
+ * Type mappings to override OpenAPI specification types and the types used in your generated code.
+ */
+ @Parameter( property = "openapi.generate.typeMappings" )
+ private List typeMappings;
+
+ /**
+ * Import mappings to specify alternative imports statement to use for a given class name.
+ */
+ @Parameter( property = "openapi.generate.importMappings" )
+ private List importMappings;
+
/**
* Defines a list of additional properties that will be passed to the Java generator.
*/
@@ -189,6 +206,8 @@ Try retrieveGenerationConfiguration()
.oneOfAnyOfGenerationEnabled(enableOneOfAnyOfGeneration)
.generateModels(generateModels)
.generateApis(generateApis)
+ .typeMappings(parseMapping(typeMappings))
+ .importMappings(parseMapping(importMappings))
.build());
}
@@ -198,4 +217,16 @@ void setOutputDirectory( final String outputDirectory )
this.outputDirectory = outputDirectory;
}
+ @Nonnull
+ private Map parseMapping( @Nonnull final List mappings )
+ {
+ return mappings
+ .stream()
+ .filter(Objects::nonNull)
+ .filter(line -> line.contains("="))
+ .map(line -> line.split("=", 2))
+ .map(parts -> new String[] { parts[0].trim(), parts[1].trim() })
+ .filter(parts -> !parts[0].isEmpty() && !parts[1].isEmpty())
+ .collect(Collectors.toMap(parts -> parts[0], parts -> parts[1]));
+ }
}
diff --git a/datamodel/openapi/openapi-generator-maven-plugin/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojoUnitTest.java b/datamodel/openapi/openapi-generator-maven-plugin/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojoUnitTest.java
index aa632f7a6..f50b73d61 100644
--- a/datamodel/openapi/openapi-generator-maven-plugin/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojoUnitTest.java
+++ b/datamodel/openapi/openapi-generator-maven-plugin/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/DataModelGeneratorMojoUnitTest.java
@@ -30,6 +30,7 @@ class DataModelGeneratorMojoUnitTest
RESOURCE_PATH + "/testInvocationWithUnexpectedApiMaturity/pom.xml";
private static final String ADDITIONAL_PROPERTIES_POM =
RESOURCE_PATH + "/testAdditionalPropertiesAndEnablingAnyOfOneOf/pom.xml";
+ private static final String MAPPINGS_EDGE_CASES_POM = RESOURCE_PATH + "/testMappingsEdgeCases/pom.xml";
@TempDir
File outputDirectory;
@@ -50,6 +51,11 @@ void testInvocationWithAllParameters( DataModelGeneratorMojo mojo )
assertThat(configuration.getApiPackage()).isEqualTo("com.sap.cloud.sdk.datamodel.rest.test.api");
assertThat(configuration.deleteOutputDirectory()).isTrue();
assertThat(configuration.isOneOfAnyOfGenerationEnabled()).isFalse();
+ assertThat(configuration.getTypeMappings())
+ .containsEntry("binary", "org.springframework.core.io.Resource")
+ .containsEntry("file", "org.springframework.core.io.Resource");
+ assertThat(configuration.getImportMappings())
+ .containsEntry("org.springframework.core.io.Resource", "org.springframework.core.io.Resource");
mojo.setOutputDirectory(outputDirectory.getAbsolutePath());
@@ -71,6 +77,8 @@ void testInvocationWithMandatoryParameters( DataModelGeneratorMojo mojo )
assertThat(configuration.getModelPackage()).isEqualTo("com.sap.cloud.sdk.datamodel.rest.test.model");
assertThat(configuration.getApiPackage()).isEqualTo("com.sap.cloud.sdk.datamodel.rest.test.api");
assertThat(configuration.deleteOutputDirectory()).isFalse();
+ assertThat(configuration.getTypeMappings()).isEmpty();
+ assertThat(configuration.getImportMappings()).isEmpty();
mojo.setOutputDirectory(outputDirectory.getAbsolutePath());
@@ -126,4 +134,21 @@ void testAdditionalPropertiesAndEnablingAnyOfOneOf( DataModelGeneratorMojo mojo
assertThat(mojo.retrieveGenerationConfiguration().get().isOneOfAnyOfGenerationEnabled()).isTrue();
}
+
+ @Test
+ @InjectMojo( goal = "generate", pom = MAPPINGS_EDGE_CASES_POM )
+ void testMappingsEdgeCases( DataModelGeneratorMojo mojo )
+ throws Throwable
+ {
+ final GenerationConfiguration configuration = mojo.retrieveGenerationConfiguration().get();
+
+ assertThat(configuration.getTypeMappings())
+ .hasSize(2) // Only valid mappings should remain
+ .containsEntry("File", "byte[]")
+ .containsEntry("binary", "org.springframework.core.io.Resource");
+
+ assertThat(configuration.getImportMappings())
+ .hasSize(1)
+ .containsEntry("Resource", "org.springframework.core.io.Resource");
+ }
}
diff --git a/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testInvocationWithAllParameters/pom.xml b/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testInvocationWithAllParameters/pom.xml
index 2ee5a9eab..589a32cbe 100644
--- a/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testInvocationWithAllParameters/pom.xml
+++ b/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testInvocationWithAllParameters/pom.xml
@@ -20,7 +20,14 @@
true
output-directory
true
-
+
+ binary=org.springframework.core.io.Resource
+ file=org.springframework.core.io.Resource
+
+
+ org.springframework.core.io.Resource=org.springframework.core.io.Resource
+
+
diff --git a/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testMappingsEdgeCases/pom.xml b/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testMappingsEdgeCases/pom.xml
new file mode 100644
index 000000000..a5cff880b
--- /dev/null
+++ b/datamodel/openapi/openapi-generator-maven-plugin/src/test/resources/DataModelGeneratorMojoUnitTest/testMappingsEdgeCases/pom.xml
@@ -0,0 +1,38 @@
+
+
+
+ 4.0.0
+ com.company
+ application
+ 5.25.0-SNAPSHOT
+
+
+
+
+ com.sap.cloud.sdk.datamodel
+ openapi-generator-maven-plugin
+
+ DataModelGeneratorMojoUnitTest/testMappingsEdgeCases/input/sodastore.yaml
+ com.sap.cloud.sdk.datamodel.rest.test.api
+ com.sap.cloud.sdk.datamodel.rest.test.model
+ released
+ output-directory
+
+ File=byte[]
+ binary = org.springframework.core.io.Resource
+ no-equals-sign
+ =missing-key
+ missing-value=
+ =
+
+
+
+ Resource=org.springframework.core.io.Resource
+ no-equals-sign
+
+
+
+
+
+
diff --git a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java
index d3406ad4a..596d8545c 100644
--- a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java
+++ b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverter.java
@@ -65,6 +65,8 @@ static ClientOptInput convertGenerationConfiguration(
config.setModelPackage(generationConfiguration.getModelPackage());
config.setTemplateDir(TEMPLATE_DIRECTORY);
config.additionalProperties().putAll(getAdditionalProperties(generationConfiguration));
+ config.typeMapping().putAll(generationConfiguration.getTypeMappings());
+ config.importMapping().putAll(generationConfiguration.getImportMappings());
final var openAPI = parseOpenApiSpec(inputSpecFile, generationConfiguration);
diff --git a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/model/GenerationConfiguration.java b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/model/GenerationConfiguration.java
index eb1c49b48..7629f856a 100644
--- a/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/model/GenerationConfiguration.java
+++ b/datamodel/openapi/openapi-generator/src/main/java/com/sap/cloud/sdk/datamodel/openapi/generator/model/GenerationConfiguration.java
@@ -61,6 +61,12 @@ public class GenerationConfiguration
@Builder.Default
boolean debugModels = false;
+ @Singular( ignoreNullCollections = true )
+ Map typeMappings;
+
+ @Singular( ignoreNullCollections = true )
+ Map importMappings;
+
/**
* Indicates whether to use the default SAP copyright header for generated files.
*
diff --git a/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverterTest.java b/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverterTest.java
index 9ad40b528..7918cc837 100644
--- a/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverterTest.java
+++ b/datamodel/openapi/openapi-generator/src/test/java/com/sap/cloud/sdk/datamodel/openapi/generator/GenerationConfigurationConverterTest.java
@@ -4,11 +4,13 @@
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Map;
import javax.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.openapitools.codegen.ClientOptInput;
import com.sap.cloud.sdk.datamodel.openapi.generator.model.GenerationConfiguration;
@@ -57,4 +59,22 @@ private String getCopyrightHeaderFromConfig( final GenerationConfiguration confi
.get(GenerationConfigurationConverter.COPYRIGHT_PROPERTY_KEY);
return maybeHeader != null ? maybeHeader.toString() : null;
}
+
+ @Test
+ @SuppressWarnings( "deprecation" )
+ void testTypeMappingsAndImportMappingsAreApplied()
+ {
+ final Map typeMappings =
+ Map.of("File", "byte[]", "binary", "org.springframework.core.io.Resource");
+ final Map importMappings = Map.of("Resource", "org.springframework.core.io.Resource");
+
+ final GenerationConfiguration config =
+ createBasicConfig().typeMappings(typeMappings).importMappings(importMappings).build();
+
+ final ClientOptInput result =
+ GenerationConfigurationConverter.convertGenerationConfiguration(config, Paths.get(config.getInputSpec()));
+
+ assertThat(result.getConfig().typeMapping()).containsAllEntriesOf(typeMappings);
+ assertThat(result.getConfig().importMapping()).containsAllEntriesOf(importMappings);
+ }
}