diff --git a/.codacy.yml b/.codacy.yml
new file mode 100644
index 00000000..c8f59295
--- /dev/null
+++ b/.codacy.yml
@@ -0,0 +1,16 @@
+---
+# Codacy configuration.
+#
+# exclude_paths accepts glob patterns relative to the repository root and removes
+# the matched files from static analysis. We exclude sources that only produce
+# false positives for this project's conventions:
+#
+# * Gradle task glue classes: thin DefaultTask subclasses. Codacy flags them for
+# "missing Javadoc", but this project does not use Javadoc, so the warning is
+# noise rather than a real defect.
+# * Generated test fixtures under src/test/resources: these are the generator's
+# expected-output files (not hand-written source) and trip rules such as
+# line-length that do not apply to generated code.
+exclude_paths:
+ - 'scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/*Task.groovy'
+ - '**/src/test/resources/**'
diff --git a/.gitignore b/.gitignore
index 7ae836cc..667f6f84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,3 +44,6 @@ pom.xml.bak
*.bak
scs-multiapi-maven-plugin/dependency-reduced-pom.xml
+
+# Internal analysis documents (not part of the plugin distribution)
+SCS-MULTIAPI-6.3.3-CODEGEN-BLOCKER.md
diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml
index ef7ec3f6..7b691435 100644
--- a/multiapi-engine/pom.xml
+++ b/multiapi-engine/pom.xml
@@ -4,7 +4,7 @@
com.sngular
multiapi-engine
- 6.4.0
+ 6.4.1
jar
diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java
index be8614ab..5e05f831 100644
--- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java
+++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java
@@ -272,7 +272,7 @@ private static List processObjectProperty(
final SchemaFieldObject field;
if (ApiTool.hasRef(fieldBody)) {
final var typeName = MapperUtil.getRefSchemaName(fieldBody, fieldName);
- final var refSchema = totalSchemas.get(MapperUtil.getRefSchemaKey(fieldBody));
+ var refSchema = totalSchemas.get(MapperUtil.getRefSchemaKey(fieldBody));
if (!antiLoopList.contains(typeName) && Objects.nonNull(refSchema) && ApiTool.hasType(refSchema)
&& ApiTool.hasItems(refSchema) || ApiTool.getRefValue(fieldBody).contains(fieldName)) {
if (antiLoopList.contains(typeName) && ApiTool.getRefValue(fieldBody).contains(fieldName)) {
diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java
index 5b8fb69a..95fd95ac 100644
--- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java
+++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java
@@ -9,7 +9,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import com.fasterxml.jackson.databind.JsonNode;
@@ -34,10 +36,16 @@ public static JsonNode solveRef(final String refValue, final Map 1) {
+ solvedRef = solvedRef.findValue(MapperUtil.getKey(refValueArr[1]));
+ }
+ }
+ if (Objects.nonNull(solvedRef) && Objects.nonNull(actualFileBase)) {
+ resolveNestedFileRefs(solvedRef, actualFileBase);
}
}
} else {
@@ -46,6 +54,71 @@ public static JsonNode solveRef(final String refValue, final Map "SCHEMAS/SERVICE_TYPE"
+ */
+ static String computeFileSchemaKey(final String refValue) {
+ try {
+ final String[] parts = refValue.split("/");
+ final String lastRaw = parts[parts.length - 1];
+ String lastName = lastRaw;
+ if (lastName.contains(".")) {
+ lastName = lastName.substring(0, lastName.indexOf('.'));
+ }
+ String category = parts.length >= 2 ? parts[parts.length - 2] : "schemas";
+ if (".".equals(category) || "..".equals(category)) {
+ category = "schemas";
+ }
+ return StringUtils.upperCase(category + "/" + StringCaseUtils.titleToSnakeCase(lastName));
+ } catch (final Exception e) {
+ return null;
+ }
+ }
+
+ private static URI resolveActualBaseUri(final URI rootFilePath, final String filePath) {
+ try {
+ final String cleaned = cleanUpPath(filePath).replace('\\', '/');
+ final Path rootPath = Paths.get(rootFilePath);
+ if (Files.exists(rootPath) && Files.isDirectory(rootPath)) {
+ return rootPath.resolve(cleaned).normalize().getParent().toUri();
+ }
+ final Path parent = rootPath.getParent();
+ if (Objects.nonNull(parent)) {
+ return parent.resolve(cleaned).normalize().getParent().toUri();
+ }
+ return null;
+ } catch (final Exception e) {
+ return null;
+ }
+ }
+
+ private static void resolveNestedFileRefs(final JsonNode node, final URI baseUri) {
+ if (Objects.isNull(node) || !node.isObject()) {
+ return;
+ }
+ final Iterator> fields = node.fields();
+ while (fields.hasNext()) {
+ final Entry field = fields.next();
+ if (field.getValue().isObject() && field.getValue().has("$ref")) {
+ final String refVal = field.getValue().get("$ref").textValue();
+ if (StringUtils.isNotEmpty(refVal) && !refVal.startsWith("#") && !refVal.startsWith("http")) {
+ try {
+ final URI nestedBase = resolveActualBaseUri(baseUri, refVal);
+ final JsonNode resolved = getPojoFromRef(baseUri, refVal);
+ if (Objects.nonNull(resolved)) {
+ field.setValue(resolved);
+ resolveNestedFileRefs(resolved, nestedBase);
+ }
+ } catch (final Exception ignored) {
+ }
+ }
+ } else {
+ resolveNestedFileRefs(field.getValue(), baseUri);
+ }
+ }
+ }
+
public static JsonNode getPojoFromRef(final URI rootFilePath, final String refPath) {
final JsonNode schemaFile;
try {
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 d1fa7daa..b8540ca6 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
@@ -6,6 +6,7 @@
package com.sngular.api.generator.plugin.openapi.utils;
+import java.net.URI;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -15,6 +16,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.BiConsumer;
import com.fasterxml.jackson.databind.JsonNode;
@@ -223,11 +225,15 @@ private static List mapRequestObject(
"InlineObject" + operationIdWithCap, globalObject, baseDir))
.build());
} else {
- final var requestBodyNode = globalObject.getRequestBodyNode(MapperUtil.getRefSchemaKey(requestBody)).orElseThrow();
+ final Optional requestBodyNode = globalObject.getRequestBodyNode(MapperUtil.getRefSchemaKey(requestBody));
+ if (requestBodyNode.isEmpty()) {
+ return requestObjects;
+ }
+ final JsonNode actualRequestBody = requestBodyNode.get();
requestObjects.add(RequestObject.builder()
.required(ApiTool.hasNode(requestBody, REQUIRED))
- .isFormData(ApiTool.getNode(requestBodyNode, CONTENT).has("multipart/form-data"))
- .contentObjects(mapContentObject(specFile, ApiTool.getNode(requestBodyNode, CONTENT),
+ .isFormData(ApiTool.getNode(actualRequestBody, CONTENT).has("multipart/form-data"))
+ .contentObjects(mapContentObject(specFile, ApiTool.getNode(actualRequestBody, CONTENT),
operationIdWithCap, globalObject, baseDir))
.build());
}
@@ -242,8 +248,11 @@ private static List mapParameterObjects(
if (Objects.nonNull(parameters) && !parameters.isEmpty()) {
for (final JsonNode parameter : parameters) {
if (ApiTool.hasRef(parameter)) {
- final JsonNode refParameter = globalObject.getParameterNode(MapperUtil.getRefSchemaKey(parameter)).orElseThrow();
- parameterObjects.add(buildParameterObject(specFile, globalObject, refParameter, baseDir));
+ final Optional optRefParameter = globalObject.getParameterNode(MapperUtil.getRefSchemaKey(parameter));
+ if (optRefParameter.isEmpty()) {
+ continue;
+ }
+ parameterObjects.add(buildParameterObject(specFile, globalObject, optRefParameter.get(), baseDir));
} else if (ApiTool.hasNode(parameter, CONTENT)) {
parameterObjects.addAll(buildParameterContent(contentClassName, parameter, specFile, globalObject, baseDir));
} else {
@@ -344,7 +353,21 @@ private static void buildResponse(
final JsonNode response) {
var realResponse = response;
if (ApiTool.hasRef(response)) {
- realResponse = globalObject.getResponseNode(MapperUtil.getRefSchemaKey(response)).orElseThrow();
+ final String refValue = ApiTool.getRefValue(response);
+ if (refValue.startsWith("#")) {
+ final Optional resolvedResponse = globalObject.getResponseNode(MapperUtil.getRefSchemaKey(response));
+ if (resolvedResponse.isEmpty()) {
+ return;
+ }
+ realResponse = resolvedResponse.get();
+ } else {
+ try {
+ final URI baseUri = baseDir.resolve(specFile.getFilePath()).getParent().toUri();
+ realResponse = SchemaUtil.getPojoFromRef(baseUri, refValue);
+ } catch (final Exception e) {
+ return;
+ }
+ }
}
final String operationIdWithCap = operationId.substring(0, 1).toUpperCase() + operationId.substring(1);
final var content = ApiTool.getNode(realResponse, CONTENT);
@@ -427,6 +450,9 @@ private static JsonNode getRefSchema(JsonNode schema, SpecFile specFile, GlobalO
if (refValue.contains("schemas")) {
refSchema = SchemaUtil.solveRef(refValue, globalObject.getSchemaMap(),
baseDir.resolve(specFile.getFilePath()).getParent().toUri());
+ if (Objects.nonNull(refSchema) && !refValue.contains("#")) {
+ globalObject.getSchemaMap().put(inlinePojoName, refSchema);
+ }
} else if (refValue.contains("requestBodies")) {
refSchema = SchemaUtil.solveRef(refValue, globalObject.getRequestBodyMap(),
baseDir.resolve(specFile.getFilePath()).getParent().toUri());
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 5403e541..7748c294 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
@@ -182,6 +182,20 @@ public final class OpenApiGeneratorFixtures {
.clientPackage("com.sngular.multifileplugin.externalpathitemref.client")
.modelNameSuffix("DTO").build());
+ static final List TEST_NESTED_EXTERNAL_REFS = List
+ .of(SpecFile.builder().filePath("openapigenerator/testNestedExternalRefs/api-test.yml")
+ .apiPackage("com.sngular.multifileplugin.testnestedexternalref")
+ .modelPackage("com.sngular.multifileplugin.testnestedexternalref.model")
+ .modelNameSuffix("DTO")
+ .useLombokModelAnnotation(true).build());
+
+ static final List TEST_NO_CONTENT_RESPONSES = List
+ .of(SpecFile.builder().filePath("openapigenerator/testNoContentResponses/api-test.yml")
+ .apiPackage("com.sngular.multifileplugin.testnocontentresponses")
+ .modelPackage("com.sngular.multifileplugin.testnocontentresponses.model")
+ .modelNameSuffix("DTO")
+ .useLombokModelAnnotation(true).build());
+
static final List TEST_ANY_OF_IN_RESPONSE = List
.of(SpecFile.builder().filePath("openapigenerator/testAnyOfInResponse/api-test.yml")
.apiPackage("com.sngular.multifileplugin.testanyofinresponse")
@@ -1370,6 +1384,37 @@ static Function validateApiWithNoComponents() {
}
+ static Function validateNestedExternalRefs() {
+ final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testnestedexternalref";
+
+ final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testnestedexternalref/model";
+
+ final String COMMON_PATH = "openapigenerator/testNestedExternalRefs/";
+
+ final List expectedTestApiFiles = List.of(COMMON_PATH + "assets/ServicesApi.java");
+
+ final List expectedTestApiModelFiles = List
+ .of(COMMON_PATH + "assets/InlineResponse200ListServicesDTO.java", COMMON_PATH + "assets/Service_typeDTO.java");
+
+ return path -> commonTest(path, expectedTestApiFiles, expectedTestApiModelFiles, DEFAULT_TARGET_API,
+ DEFAULT_MODEL_API, Collections.emptyList(), null);
+ }
+
+ static Function validateNoContentResponses() {
+ final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testnocontentresponses";
+
+ final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testnocontentresponses/model";
+
+ final String COMMON_PATH = "openapigenerator/testNoContentResponses/";
+
+ final List expectedTestApiFiles = List.of(COMMON_PATH + "assets/ItemsApi.java");
+
+ final List expectedTestApiModelFiles = List.of(COMMON_PATH + "assets/ItemDTO.java");
+
+ return path -> commonTest(path, expectedTestApiFiles, expectedTestApiModelFiles, DEFAULT_TARGET_API,
+ DEFAULT_MODEL_API, Collections.emptyList(), null);
+ }
+
private static Boolean commonTest(final Path resultPath, final List expectedFile,
final List expectedModelFiles, final String targetApi, final String targetModel,
final List expectedExceptionFiles, final String targetException) {
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 72588900..723356a0 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
@@ -93,6 +93,10 @@ static Stream fileSpecToProcess() {
OpenApiGeneratorFixtures.validateWebhookPathCollision()),
Arguments.of("testExternalPathItemRefsGeneration", OpenApiGeneratorFixtures.TEST_EXTERNAL_PATH_ITEM_REF_GENERATION,
OpenApiGeneratorFixtures.validateExternalPathItemRefGeneration()),
+ Arguments.of("testNestedExternalRefs", OpenApiGeneratorFixtures.TEST_NESTED_EXTERNAL_REFS,
+ OpenApiGeneratorFixtures.validateNestedExternalRefs()),
+ Arguments.of("testNoContentResponses", OpenApiGeneratorFixtures.TEST_NO_CONTENT_RESPONSES,
+ OpenApiGeneratorFixtures.validateNoContentResponses()),
Arguments.of("testAnyOfInResponse", OpenApiGeneratorFixtures.TEST_ANY_OF_IN_RESPONSE,
OpenApiGeneratorFixtures.validateAnyOfInResponse()),
Arguments.of("testOneOfInResponse", OpenApiGeneratorFixtures.TEST_ONE_OF_IN_RESPONSE,
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml
new file mode 100644
index 00000000..2ccacf17
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml
@@ -0,0 +1,23 @@
+---
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Nested External Ref Test
+ license:
+ name: MIT
+servers:
+ - url: http://localhost:8080/v1
+paths:
+ /services:
+ get:
+ summary: List all services
+ operationId: listServices
+ tags:
+ - services
+ responses:
+ '200':
+ description: A list of services
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/Service.yml"
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java
new file mode 100644
index 00000000..e3fc7680
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java
@@ -0,0 +1,26 @@
+package com.sngular.multifileplugin.testnestedexternalref.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Value;
+import lombok.extern.jackson.Jacksonized;
+
+@Value
+public class InlineResponse200ListServicesDTO {
+
+ @JsonProperty(value ="service_id")
+ private String service_id;
+
+ @JsonProperty(value ="service_type")
+ private Service_typeDTO service_type;
+
+
+ @Builder
+ @Jacksonized
+ private InlineResponse200ListServicesDTO(String service_id, Service_typeDTO service_type) {
+ this.service_id = service_id;
+ this.service_type = service_type;
+
+ }
+
+}
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java
new file mode 100644
index 00000000..e7afd75e
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java
@@ -0,0 +1,26 @@
+package com.sngular.multifileplugin.testnestedexternalref.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Value;
+import lombok.extern.jackson.Jacksonized;
+
+@Value
+public class Service_typeDTO {
+
+ @JsonProperty(value ="type_code")
+ private Integer type_code;
+
+ @JsonProperty(value ="type_name")
+ private String type_name;
+
+
+ @Builder
+ @Jacksonized
+ private Service_typeDTO(Integer type_code, String type_name) {
+ this.type_code = type_code;
+ this.type_name = type_name;
+
+ }
+
+}
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java
new file mode 100644
index 00000000..e85b1d96
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java
@@ -0,0 +1,46 @@
+package com.sngular.multifileplugin.testnestedexternalref;
+
+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 com.sngular.multifileplugin.testnestedexternalref.model.InlineResponse200ListServicesDTO;
+
+public interface ServicesApi {
+
+ /**
+ * GET /services: List all services
+ * @return A list of services; (status code 200)
+ */
+
+ @Operation(
+ operationId = "listServices",
+ summary = "List all services",
+ tags = {"services"},
+ responses = {
+ @ApiResponse(responseCode = "200", description = "A list of services", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InlineResponse200ListServicesDTO.class)))
+ }
+ )
+ @RequestMapping(
+ method = RequestMethod.GET,
+ value = "/services",
+ produces = {"application/json"}
+ )
+
+ default ResponseEntity listServices() {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+}
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml
new file mode 100644
index 00000000..8ff24350
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml
@@ -0,0 +1,7 @@
+---
+type: object
+properties:
+ service_id:
+ type: string
+ service_type:
+ $ref: './ServiceType.yml'
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml
new file mode 100644
index 00000000..3ee826f5
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml
@@ -0,0 +1,8 @@
+---
+type: object
+properties:
+ type_code:
+ type: integer
+ format: int32
+ type_name:
+ type: string
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml
new file mode 100644
index 00000000..05ef0823
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml
@@ -0,0 +1,57 @@
+---
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: No Content Responses Test
+ license:
+ name: MIT
+servers:
+ - url: http://localhost:8080/v1
+paths:
+ /items:
+ get:
+ summary: List items
+ operationId: listItems
+ tags:
+ - items
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Item'
+ '204':
+ $ref: '#/components/responses/NoContent'
+ '401':
+ $ref: '#/components/responses/Unauthorized'
+ /items/{itemId}:
+ delete:
+ summary: Delete item
+ operationId: deleteItem
+ tags:
+ - items
+ responses:
+ '204':
+ $ref: '#/components/responses/NoContent'
+ '404':
+ $ref: '#/components/responses/NotFound'
+components:
+ schemas:
+ Item:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int32
+ name:
+ type: string
+ responses:
+ NoContent:
+ description: No content
+ Unauthorized:
+ description: Unauthorized access
+ NotFound:
+ description: Resource not found
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java
new file mode 100644
index 00000000..0fb28d19
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java
@@ -0,0 +1,26 @@
+package com.sngular.multifileplugin.testnocontentresponses.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Value;
+import lombok.extern.jackson.Jacksonized;
+
+@Value
+public class ItemDTO {
+
+ @JsonProperty(value ="name")
+ private String name;
+
+ @JsonProperty(value ="id")
+ private Integer id;
+
+
+ @Builder
+ @Jacksonized
+ private ItemDTO(String name, Integer id) {
+ this.name = name;
+ this.id = id;
+
+ }
+
+}
diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java
new file mode 100644
index 00000000..a87c7f5f
--- /dev/null
+++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java
@@ -0,0 +1,71 @@
+package com.sngular.multifileplugin.testnocontentresponses;
+
+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 com.sngular.multifileplugin.testnocontentresponses.model.ItemDTO;
+
+public interface ItemsApi {
+
+ /**
+ * GET /items: List items
+ * @return Successful response; (status code 200) No content; (status code 204) Unauthorized access; (status code 401)
+ */
+
+ @Operation(
+ operationId = "listItems",
+ summary = "List items",
+ tags = {"items"},
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Successful response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = List.class))),
+ @ApiResponse(responseCode = "204", description = "No content"),
+ @ApiResponse(responseCode = "401", description = "Unauthorized access")
+ }
+ )
+ @RequestMapping(
+ method = RequestMethod.GET,
+ value = "/items",
+ produces = {"application/json"}
+ )
+
+ default ResponseEntity> listItems() {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+ /**
+ * DELETE /items/{itemId}: Delete item
+ * @return No content; (status code 204) Resource not found; (status code 404)
+ */
+
+ @Operation(
+ operationId = "deleteItem",
+ summary = "Delete item",
+ tags = {"items"},
+ responses = {
+ @ApiResponse(responseCode = "204", description = "No content"),
+ @ApiResponse(responseCode = "404", description = "Resource not found")
+ }
+ )
+ @RequestMapping(
+ method = RequestMethod.DELETE,
+ value = "/items/{itemId}",
+ produces = {"application/json"}
+ )
+
+ default ResponseEntity deleteItem() {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+}
diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle
index 67976a57..129e16cd 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.4.0'
+version = '6.4.1'
def SCSMultiApiPluginGroupId = group
def SCSMultiApiPluginVersion = version
@@ -31,7 +31,7 @@ dependencies {
shadow localGroovy()
shadow gradleApi()
- implementation 'com.sngular:multiapi-engine:6.4.0'
+ implementation 'com.sngular:multiapi-engine:6.4.1'
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.4.0'
+ implementation 'com.sngular:scs-multiapi-gradle-plugin:6.4.1'
implementation 'org.assertj:assertj-core:3.24.2'
}
diff --git a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy
index 2eab7796..7261441e 100644
--- a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy
+++ b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy
@@ -19,7 +19,7 @@ import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault
-@DisableCachingByDefault(because = "Generation depends on external spec files that are not declared as cacheable inputs")
+@DisableCachingByDefault(because = "Generation depends on external spec files not declared as cacheable inputs")
abstract class AsyncApiTask extends DefaultTask {
@Optional
diff --git a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy
index f5b13937..d31a2493 100644
--- a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy
+++ b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy
@@ -18,7 +18,7 @@ import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault
-@DisableCachingByDefault(because = "Generation depends on external spec files that are not declared as cacheable inputs")
+@DisableCachingByDefault(because = "Generation depends on external spec files not declared as cacheable inputs")
abstract class OpenApiTask extends DefaultTask {
@Optional
diff --git a/scs-multiapi-maven-plugin/pom.xml b/scs-multiapi-maven-plugin/pom.xml
index b9e8fd8b..6f3c5e7f 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.4.0
+ 6.4.1
maven-plugin
AsyncApi - OpenApi Code Generator Maven Plugin
@@ -271,7 +271,7 @@
com.sngular
multiapi-engine
- 6.4.0
+ 6.4.1
org.apache.maven