diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml
index 73b8563e..f9aa78e0 100644
--- a/multiapi-engine/pom.xml
+++ b/multiapi-engine/pom.xml
@@ -4,7 +4,7 @@
com.sngular
multiapi-engine
- 6.6.3
+ 6.6.4
jar
diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/SchemaFieldObjectType.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/SchemaFieldObjectType.java
index 72bed1be..291bb3fb 100644
--- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/SchemaFieldObjectType.java
+++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/SchemaFieldObjectType.java
@@ -38,7 +38,8 @@ public class SchemaFieldObjectType {
new SimpleImmutableEntry<>(TypeConstants.ZONEDDATETIME, ZONED_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATE, OFFSET_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATETIME, OFFSET_DATE_TIME),
- new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile")
+ new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile"),
+ new SimpleImmutableEntry<>(TypeConstants.RESOURCE, "Resource")
);
private static final Map IMPORT_TYPE_MAPPINGS = Map.ofEntries(
@@ -53,7 +54,8 @@ public class SchemaFieldObjectType {
new SimpleImmutableEntry<>(TypeConstants.ZONEDDATETIME, "java.time." + ZONED_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATE, "java.time." + OFFSET_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATETIME, "java.time." + OFFSET_DATE_TIME),
- new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile")
+ new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile"),
+ new SimpleImmutableEntry<>(TypeConstants.RESOURCE, "org.springframework.core.io.Resource")
);
private static final Map IMPL_TYPE_MAPPINGS = Map.ofEntries(
@@ -73,7 +75,8 @@ public class SchemaFieldObjectType {
new SimpleImmutableEntry<>(TypeConstants.ZONEDDATETIME, ZONED_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATE, OFFSET_DATE_TIME),
new SimpleImmutableEntry<>(TypeConstants.OFFSETDATETIME, OFFSET_DATE_TIME),
- new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile")
+ new SimpleImmutableEntry<>(TypeConstants.MULTIPART_FILE, "MultipartFile"),
+ new SimpleImmutableEntry<>(TypeConstants.RESOURCE, "Resource")
);
private final String baseType;
diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/TypeConstants.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/TypeConstants.java
index 7b98ed51..c3db8182 100644
--- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/TypeConstants.java
+++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/model/TypeConstants.java
@@ -56,6 +56,8 @@ public final class TypeConstants {
public static final String MULTIPART_FILE = "multipartfile";
+ public static final String RESOURCE = "resource";
+
public static final Set BASIC_OBJECT_TYPE = Set.of(NUMBER, STRING, BOOLEAN, INTEGER, ARRAY);
public static final Set NO_IMPORT_TYPE = Set.of(STRING, INTEGER, OBJECT);
@@ -94,7 +96,8 @@ public final class TypeConstants {
ZONEDDATETIME,
OFFSETDATE,
OFFSETDATETIME,
- MULTIPART_FILE
+ MULTIPART_FILE,
+ RESOURCE
);
private TypeConstants() {
diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java
index b8540ca6..c42de51e 100644
--- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java
+++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java
@@ -473,6 +473,11 @@ private static JsonNode getRefSchema(JsonNode schema, SpecFile specFile, GlobalO
private static SchemaFieldObjectType getObjectOrType(
final JsonNode schema, final String pojoName, final SpecFile specFile, final GlobalObject globalObject,
final Path baseDir) {
+ if (ApiTool.isBinary(schema)) {
+ // A raw binary body (e.g. application/octet-stream, type: string + format: binary,
+ // not wrapped in a multipart object) maps to a streaming Resource, not String.
+ return new SchemaFieldObjectType(TypeConstants.RESOURCE);
+ }
return switch (ApiTool.getType(schema)) {
case TypeConstants.OBJECT -> SchemaFieldObjectType.fromTypeList(TypeConstants.OBJECT, pojoName);
case TypeConstants.INTEGER -> new SchemaFieldObjectType(getIntegerFormat(schema));
diff --git a/multiapi-engine/src/main/resources/templates/openapi/template.ftlh b/multiapi-engine/src/main/resources/templates/openapi/template.ftlh
index cca53a5d..86ce833a 100644
--- a/multiapi-engine/src/main/resources/templates/openapi/template.ftlh
+++ b/multiapi-engine/src/main/resources/templates/openapi/template.ftlh
@@ -4,6 +4,7 @@ package <#if packageApi??>${packageApi}<#elseif package??> ${package}#if>;
<#assign imports=[]>
<#assign model_imports=[]>
<#assign needsMultipartFile=false>
+<#assign needsResource=false>
<#list pathObjects as path>
<#list path.operationObjects as operation>
<#list operation.requestObjects as request>
@@ -18,6 +19,18 @@ package <#if packageApi??>${packageApi}<#elseif package??> ${package}#if>;
#if>
#list>
#if>
+ <#list request.contentObjects as content>
+ <#if content.dataType.containsType("resource")>
+ <#assign needsResource=true>
+ #if>
+ #list>
+ #list>
+ <#list operation.responseObjects as response>
+ <#list response.contentObjects as content>
+ <#if content.dataType.containsType("resource")>
+ <#assign needsResource=true>
+ #if>
+ #list>
#list>
#list>
#list>
@@ -85,6 +98,9 @@ import org.springframework.web.context.request.NativeWebRequest;
<#if needsMultipartFile>
import org.springframework.web.multipart.MultipartFile;
#if>
+<#if needsResource>
+import org.springframework.core.io.Resource;
+#if>
<#list model_imports as import>
import <#if packageModel??>${packageModel}<#elseif package??>${package}#if>.${import};
diff --git a/multiapi-engine/src/main/resources/templates/openapi/templateReactive.ftlh b/multiapi-engine/src/main/resources/templates/openapi/templateReactive.ftlh
index 7f56c742..ab3b5d94 100644
--- a/multiapi-engine/src/main/resources/templates/openapi/templateReactive.ftlh
+++ b/multiapi-engine/src/main/resources/templates/openapi/templateReactive.ftlh
@@ -23,6 +23,7 @@ import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;
import springfox.documentation.annotations.ApiIgnore;
<#assign needsFilePart=false>
+<#assign needsResource=false>
<#list pathObjects as path>
<#list path.operationObjects as operation>
<#list operation.requestObjects as request>
@@ -37,12 +38,27 @@ import springfox.documentation.annotations.ApiIgnore;
#if>
#list>
#if>
+ <#list request.contentObjects as content>
+ <#if content.dataType.containsType("resource")>
+ <#assign needsResource=true>
+ #if>
+ #list>
+ #list>
+ <#list operation.responseObjects as response>
+ <#list response.contentObjects as content>
+ <#if content.dataType.containsType("resource")>
+ <#assign needsResource=true>
+ #if>
+ #list>
#list>
#list>
#list>
<#if needsFilePart>
import org.springframework.http.codec.multipart.FilePart;
#if>
+<#if needsResource>
+import org.springframework.core.io.Resource;
+#if>
<#assign imports=[]>
<#list pathObjects as path>
diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java
index 3b66654a..3af6ff97 100644
--- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java
+++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java
@@ -86,6 +86,16 @@ public final class OpenApiGeneratorFixtures {
.apiPackage("com.sngular.multifileplugin.testreactiveformdatamultipart")
.useLombokModelAnnotation(false).isReactive(true).build());
+ static final List TEST_BINARY_BODY_RESOURCE = List
+ .of(SpecFile.builder().filePath("openapigenerator/testBinaryBodyResource/api-test.yml")
+ .apiPackage("com.sngular.multifileplugin.testbinarybodyresource")
+ .useLombokModelAnnotation(false).build());
+
+ static final List TEST_REACTIVE_BINARY_BODY_RESOURCE = List
+ .of(SpecFile.builder().filePath("openapigenerator/testReactiveBinaryBodyResource/api-test.yml")
+ .apiPackage("com.sngular.multifileplugin.testreactivebinarybodyresource")
+ .useLombokModelAnnotation(false).isReactive(true).build());
+
static final List TEST_API_TAGS_GENERATION = List
.of(SpecFile.builder().filePath("openapigenerator/testApiTagsGeneration/api-tags-test.yml")
.apiPackage("com.sngular.multifileplugin.tagsgeneration")
@@ -607,6 +617,38 @@ static Function validateApiReactiveGeneration(int springBootVersi
}
+ static Function validateBinaryBodyResource() {
+
+ final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testbinarybodyresource";
+
+ final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testbinarybodyresource/model";
+
+ final String COMMON_PATH = "openapigenerator/testBinaryBodyResource/";
+
+ final String ASSETS_PATH = COMMON_PATH + "assets/";
+
+ final List expectedTestApiFile = List.of(ASSETS_PATH + "UploadApi.java");
+
+ return path -> commonTest(path, expectedTestApiFile, Collections.emptyList(), DEFAULT_TARGET_API,
+ DEFAULT_MODEL_API, Collections.emptyList(), null);
+ }
+
+ static Function validateReactiveBinaryBodyResource() {
+
+ final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testreactivebinarybodyresource";
+
+ final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testreactivebinarybodyresource/model";
+
+ final String COMMON_PATH = "openapigenerator/testReactiveBinaryBodyResource/";
+
+ final String ASSETS_PATH = COMMON_PATH + "assets/";
+
+ final List expectedTestApiFile = List.of(ASSETS_PATH + "UploadApi.java");
+
+ return path -> commonTest(path, expectedTestApiFile, Collections.emptyList(), DEFAULT_TARGET_API,
+ DEFAULT_MODEL_API, Collections.emptyList(), null);
+ }
+
static Function validateReactiveFormDataMultipart() {
final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testreactiveformdatamultipart";
diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java
index 4bfa1dac..e5a9b604 100644
--- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java
+++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java
@@ -65,6 +65,10 @@ static Stream fileSpecToProcess() {
OpenApiGeneratorFixtures.validateApiReactiveGeneration(SPRING_BOOT_VERSION)),
Arguments.of("testReactiveFormDataMultipart", OpenApiGeneratorFixtures.TEST_REACTIVE_FORM_DATA_MULTIPART,
OpenApiGeneratorFixtures.validateReactiveFormDataMultipart()),
+ Arguments.of("testBinaryBodyResource", OpenApiGeneratorFixtures.TEST_BINARY_BODY_RESOURCE,
+ OpenApiGeneratorFixtures.validateBinaryBodyResource()),
+ Arguments.of("testReactiveBinaryBodyResource", OpenApiGeneratorFixtures.TEST_REACTIVE_BINARY_BODY_RESOURCE,
+ OpenApiGeneratorFixtures.validateReactiveBinaryBodyResource()),
Arguments.of("testApiTagsGeneration", OpenApiGeneratorFixtures.TEST_API_TAGS_GENERATION,
OpenApiGeneratorFixtures.validateTagsGeneration()),
Arguments.of("testMultipleRefGeneration", OpenApiGeneratorFixtures.TEST_MULTIPLE_REF_GENERATION,
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/api-test.yml
new file mode 100644
index 00000000..257a0157
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/api-test.yml
@@ -0,0 +1,23 @@
+openapi: 3.0.2
+info:
+ title: Testing raw binary request body
+ version: 1.0.0
+servers:
+- url: http://localhost/v1
+paths:
+ /upload:
+ post:
+ tags:
+ - test
+ operationId: uploadBinary
+ requestBody:
+ required: true
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ '200':
+ description:
+ OK
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/assets/UploadApi.java b/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/assets/UploadApi.java
new file mode 100644
index 00000000..50be0b6a
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testBinaryBodyResource/assets/UploadApi.java
@@ -0,0 +1,46 @@
+package com.sngular.multifileplugin.testbinarybodyresource;
+
+import java.util.Optional;
+import java.util.List;
+import java.util.Map;
+import javax.validation.Valid;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import org.springframework.http.MediaType;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.core.io.Resource;
+
+
+public interface UploadApi {
+
+ /**
+ * POST /upload
+ * @param resource (required)
+ * @return OK; (status code 200)
+ */
+
+ @Operation(
+ operationId = "uploadBinary",
+ tags = {"test"},
+ responses = {
+ @ApiResponse(responseCode = "200", description = "OK")
+ }
+ )
+ @RequestMapping(
+ method = RequestMethod.POST,
+ value = "/upload",
+ produces = {"application/json"}
+ )
+
+ default ResponseEntity uploadBinary(@Parameter(name = "resource", description = "", required = true, schema = @Schema(description = "")) @Valid @RequestBody Resource resource) {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+}
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/api-test.yml
new file mode 100644
index 00000000..7441748e
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/api-test.yml
@@ -0,0 +1,23 @@
+openapi: 3.0.2
+info:
+ title: Testing reactive raw binary request body
+ version: 1.0.0
+servers:
+- url: http://localhost/v1
+paths:
+ /upload:
+ post:
+ tags:
+ - test
+ operationId: uploadBinary
+ requestBody:
+ required: true
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ '200':
+ description:
+ OK
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/assets/UploadApi.java b/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/assets/UploadApi.java
new file mode 100644
index 00000000..2235f657
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testReactiveBinaryBodyResource/assets/UploadApi.java
@@ -0,0 +1,50 @@
+package com.sngular.multifileplugin.testreactivebinarybodyresource;
+
+import java.util.List;
+import java.util.Map;
+import java.nio.charset.StandardCharsets;
+import javax.validation.Valid;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import org.springframework.http.MediaType;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.core.io.buffer.DefaultDataBufferFactory;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.Flux;
+import springfox.documentation.annotations.ApiIgnore;
+import org.springframework.core.io.Resource;
+
+
+public interface UploadApi {
+
+ /**
+ * POST /upload
+ * @param resource (required)
+ * @return OK; (status code 200)
+ * @throws WebClientResponseException if an error occurs while attempting to invoke the API
+ */
+ @Operation(
+ operationId = "uploadBinary",
+ tags = {"test"},
+ responses = {
+ @ApiResponse(responseCode = "200", description = "OK")
+ }
+ )
+ @RequestMapping(
+ method = RequestMethod.POST,
+ value = "/upload",
+ produces = {"application/json"}
+ )
+ default ResponseEntity uploadBinary(@Parameter(name = "resource", description = "", required = true, schema = @Schema(description = "")) @Valid @RequestBody Mono resource, @ApiIgnore final ServerWebExchange exchange) {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+}
\ No newline at end of file
diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle
index 68e961a3..c5225e0e 100644
--- a/scs-multiapi-gradle-plugin/build.gradle
+++ b/scs-multiapi-gradle-plugin/build.gradle
@@ -21,7 +21,7 @@ repositories {
}
group = 'com.sngular'
-version = '6.6.3'
+version = '6.6.4'
def SCSMultiApiPluginGroupId = group
def SCSMultiApiPluginVersion = version
@@ -31,7 +31,7 @@ dependencies {
shadow localGroovy()
shadow gradleApi()
- implementation 'com.sngular:multiapi-engine:6.6.3'
+ implementation 'com.sngular:multiapi-engine:6.6.4'
testImplementation 'org.assertj:assertj-core:3.24.2'
testImplementation 'com.puppycrawl.tools:checkstyle:10.12.3'
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.2'
@@ -100,7 +100,7 @@ testing {
integrationTest(JvmTestSuite) {
dependencies {
- implementation 'com.sngular:scs-multiapi-gradle-plugin:6.6.3'
+ implementation 'com.sngular:scs-multiapi-gradle-plugin:6.6.4'
implementation 'org.assertj:assertj-core:3.24.2'
}
diff --git a/scs-multiapi-maven-plugin/pom.xml b/scs-multiapi-maven-plugin/pom.xml
index 27bc47e7..230e9c80 100644
--- a/scs-multiapi-maven-plugin/pom.xml
+++ b/scs-multiapi-maven-plugin/pom.xml
@@ -4,7 +4,7 @@
com.sngular
scs-multiapi-maven-plugin
- 6.6.3
+ 6.6.4
maven-plugin
AsyncApi - OpenApi Code Generator Maven Plugin
@@ -271,7 +271,7 @@
com.sngular
multiapi-engine
- 6.6.3
+ 6.6.4
org.apache.maven