diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml index ca51f409..d9368599 100644 --- a/multiapi-engine/pom.xml +++ b/multiapi-engine/pom.xml @@ -4,7 +4,7 @@ com.sngular multiapi-engine - 6.7.3 + 6.7.4 jar diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ApiTool.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ApiTool.java index 4397ce00..d9309609 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ApiTool.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ApiTool.java @@ -417,6 +417,26 @@ public static JsonNode getPatternProperties(final JsonNode schema) { return getNode(schema, "patternProperties"); } + public static boolean isInlineObject(final JsonNode schema) { + return Objects.nonNull(schema) && schema.isObject() && !hasType(schema) && !hasNode(schema, "properties") + && !hasNode(schema, "$ref") && !isComposed(schema) && !hasNode(schema, "items") && !hasNode(schema, "enum") + && !hasNode(schema, "additionalProperties") && !hasNode(schema, "patternProperties") + && hasNonSchemaFields(schema); + } + + private static boolean hasNonSchemaFields(final JsonNode schema) { + final Iterator> fields = schema.fields(); + return fields.hasNext() && !isSchemaKeyword(fields.next().getKey()); + } + + private static boolean isSchemaKeyword(final String fieldName) { + return "type".equals(fieldName) || "title".equals(fieldName) || "description".equals(fieldName) + || "required".equals(fieldName) || "nullable".equals(fieldName) || "deprecated".equals(fieldName) + || "example".equals(fieldName) || "default".equals(fieldName) || "format".equals(fieldName) + || "const".equals(fieldName) || "readOnly".equals(fieldName) || "writeOnly".equals(fieldName) + || "discriminator".equals(fieldName) || "xml".equals(fieldName) || "externalDocs".equals(fieldName); + } + public static boolean hasPrefixItems(final JsonNode schema) { return hasNode(schema, "prefixItems"); } 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 1951328a..67b509d6 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 @@ -187,6 +187,8 @@ private static Set getFields( final var refSchema = totalSchemas.get(MapperUtil.getRefSchemaKey(schema)); ApiTool.getProperties(refSchema).forEachRemaining(processProperties(buildingSchema, totalSchemas, compositedSchemas, fieldObjectArrayList, specFile, refSchema, antiLoopList, baseDir)); + } else if (ApiTool.isInlineObject(schema)) { + schema.fields().forEachRemaining(processProperties(nameSchema, totalSchemas, compositedSchemas, fieldObjectArrayList, specFile, schema, antiLoopList, baseDir)); } else { fieldObjectArrayList.add(SchemaFieldObject.builder() .baseName(ApiTool.getName(schema)) diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorFixtures.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorFixtures.java index 38243d97..6b52d9d0 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorFixtures.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorFixtures.java @@ -9,11 +9,14 @@ import static java.util.Collections.singletonList; import java.io.File; +import java.io.IOException; import java.net.URISyntaxException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.function.Function; +import java.util.stream.Stream; import com.sngular.api.generator.plugin.asyncapi.parameter.OperationParameterObject; import com.sngular.api.generator.plugin.asyncapi.parameter.SpecFile; @@ -145,6 +148,25 @@ public class AsyncApiGeneratorFixtures { .build() ); + static final List TEST_ISSUE_248_GENERATION = List.of( + SpecFile + .builder() + .filePath("asyncapigenerator/v2/testIssueCustomValidators248/event-api.yml") + .consumer(OperationParameterObject.builder() + .ids("publishOrder") + .modelNameSuffix("DTO") + .apiPackage("com.sngular.scsplugin.issue248.model.event.consumer") + .modelPackage("com.sngular.scsplugin.issue248.model.event") + .build()) + .supplier(OperationParameterObject.builder() + .ids("subscribeOrder") + .modelNameSuffix("DTO") + .apiPackage("com.sngular.scsplugin.issue248.model.event.producer") + .modelPackage("com.sngular.scsplugin.issue248.model.event") + .build()) + .build() + ); + static final List TEST_CUSTOM_VALIDATORS_DIFFERENT_PACKAGES = List.of( SpecFile .builder() @@ -754,6 +776,34 @@ static Function validateCustomValidators(final int springBootVers customValidatorTest(path, expectedValidatorFiles, DEFAULT_CUSTOM_VALIDATOR_FOLDER); } + static Function validateIssue248PackageFolderAlignment() { + return path -> { + final Path pathToTarget = Path.of(path.toString(), "target", "generated"); + Boolean result = Boolean.TRUE; + try (final Stream javaFiles = Files.walk(pathToTarget)) { + final List generatedFiles = javaFiles + .filter(Files::isRegularFile) + .filter(p -> p.toString().endsWith(".java")) + .toList(); + Assertions.assertThat(generatedFiles).isNotEmpty(); + for (final Path javaFile : generatedFiles) { + final String packageDeclaration = Files.readAllLines(javaFile).stream() + .filter(line -> line.startsWith("package ")) + .findFirst() + .map(line -> line.replace("package ", "").replace(";", "").trim()) + .orElseThrow(); + final String expectedPackage = pathToTarget.relativize(javaFile).getParent().toString().replace(File.separatorChar, '.'); + Assertions.assertThat(packageDeclaration) + .overridingErrorMessage("File %s declares package %s but lives in folder matching %s", javaFile, packageDeclaration, expectedPackage) + .isEqualTo(expectedPackage); + } + } catch (final IOException e) { + result = Boolean.FALSE; + } + return result; + }; + } + static Function validateCustomValidatorsDifferentPackages() { final String DEFAULT_CONSUMER_MODEL_FOLDER = "generated/com/sngular/scsplugin/customvalidatordiff/model/event/consumer"; diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorTest.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorTest.java index 634db9aa..88df2c9e 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorTest.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/v2/AsyncApiGeneratorTest.java @@ -70,6 +70,8 @@ static Stream fileSpecToProcess() { Arguments.of("TestCustomValidators", AsyncApiGeneratorFixtures.TEST_CUSTOM_VALIDATORS, AsyncApiGeneratorFixtures.validateCustomValidators(SPRING_BOOT_VERSION)), Arguments.of("TestCustomValidatorsDifferentPackages", AsyncApiGeneratorFixtures.TEST_CUSTOM_VALIDATORS_DIFFERENT_PACKAGES, AsyncApiGeneratorFixtures.validateCustomValidatorsDifferentPackages()), + Arguments.of("TestIssue248CustomValidators", AsyncApiGeneratorFixtures.TEST_ISSUE_248_GENERATION, + AsyncApiGeneratorFixtures.validateIssue248PackageFolderAlignment()), Arguments.of("TestModelClassExceptionGeneration", AsyncApiGeneratorFixtures.TEST_MODEL_CLASS_EXCEPTION_GENERATION, AsyncApiGeneratorFixtures.validateTestModelClassExceptionGeneration()), Arguments.of("TestNoSchemas", AsyncApiGeneratorFixtures.TEST_NO_SCHEMAS, AsyncApiGeneratorFixtures.validateNoSchemas()), diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/v2/testIssueCustomValidators248/event-api.yml b/multiapi-engine/src/test/resources/asyncapigenerator/v2/testIssueCustomValidators248/event-api.yml new file mode 100644 index 00000000..70f75b1a --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/v2/testIssueCustomValidators248/event-api.yml @@ -0,0 +1,98 @@ +asyncapi: 2.3.0 +info: + title: Order Service + version: 1.0.0 + description: Order management Service +servers: + development: + url: development.gigantic-server.com + description: Development server + protocol: kafka + protocolVersion: 0.9.1 + staging: + url: staging.gigantic-server.com + description: Staging server + protocol: kafka + protocolVersion: 0.9.1 + production: + url: api.gigantic-server.com + description: Production server + protocol: kafka + protocolVersion: 0.9.1 +channels: + order/created: + publish: + operationId: "publishOrder" + message: + $ref: '#/components/messages/OrderCreatedEvent' + order/createCommand: + subscribe: + operationId: "subscribeOrder" + message: + $ref: '#/components/messages/CreateOrderEvent' +components: + messages: + OrderCreatedEvent: + payload: + $ref: '#/components/schemas/Order' + CreateOrderEvent: + payload: + order: + $ref: '#/components/schemas/Order' + waiter: + $ref: '#/components/schemas/Waiter' + schemas: + Waiter: + type: object + properties: + ref: + type: string + timestamp: + type: string + format: 'dd/mm/yyyy hh:MM:sss' + table: + type: string + Order: + type: object + properties: + ref: + type: string + clientRef: + type: string + amount: + type: string + format: decimal + lines: + type: array + items: + $ref: '#/components/schemas/OrderLine' + OrderLine: + type: object + required: + - ref + - products + properties: + ref: + type: string + products: + type: array + items: + $ref: '#/components/schemas/OrderProduct' + OrderProduct: + type: object + required: + - ref + - productRef + - price + - quantity + properties: + ref: + type: string + productRef: + type: string + price: + type: string + format: decimal + quantity: + type: string + format: decimal diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle index 26780f99..64415ba8 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.7.3' +version = '6.7.4' def SCSMultiApiPluginGroupId = group def SCSMultiApiPluginVersion = version @@ -31,7 +31,7 @@ dependencies { shadow localGroovy() shadow gradleApi() - implementation 'com.sngular:multiapi-engine:6.7.3' + implementation 'com.sngular:multiapi-engine:6.7.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.7.3' + implementation 'com.sngular:scs-multiapi-gradle-plugin:6.7.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 39a9ef94..a2a7ac93 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.7.3 + 6.7.4 maven-plugin AsyncApi - OpenApi Code Generator Maven Plugin @@ -271,7 +271,7 @@ com.sngular multiapi-engine - 6.7.3 + 6.7.4 org.apache.maven