diff --git a/README.md b/README.md index ed77c1c8..0805516f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ As commented above, they both could be used at the same time, setting a double com.sngular scs-multiapi-maven-plugin - 5.4.2 + 5.4.3 asyncapi @@ -104,6 +104,32 @@ In the [AsyncApi Generator](#asyncapi-generator) and the [OpenApi Generator](#openapi-generator) sections, you can find more information about how they work, and the parameters and configuration options they offer. +#### Mandatory dependencies + +These dependencies are used by generated code + +```xml + + + io.swagger.parser.v3 + swagger-parser-core + 2.1.20 + + + + io.swagger.core.v3 + swagger-annotations-jakarta + 2.2.20 + + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + +``` + ### How to configure the build file To maintain the generation of the different types of classes independent, they @@ -114,7 +140,7 @@ Apply the plugin in the `build.gradle` file and invoke the task. ```groovy plugins { id "java" - id "com.sngular.scs-multiapi-gradle-plugin' version '5.4.2" + id "com.sngular.scs-multiapi-gradle-plugin' version '5.4.3" openapimodel { @@ -138,6 +164,16 @@ In the [AsyncApi Generator](#asyncapi-generator) and the [OpenApi Generator](#openapi-generator) sections, you can find more information about how they work, and the parameters and configuration options they offer. +#### Mandatory gradle dependencies + +These dependencies are used by generated code + +``` gradle +implementation 'io.swagger.parser.v3:swagger-parser-core:2.1.20' +implementation 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.20' +implementation 'jakarta.validation:jakarta.validation-api:3.0.2' +``` + ## AsyncApi Generator ### Configuration @@ -153,7 +189,7 @@ which the plugin is designed. com.sngular scs-multiapi-maven-plugin - 5.4.2 + 5.4.3 generate-sources @@ -443,8 +479,16 @@ public interface ISubscribeOperation { #### Bindings -Asyncapi support a way to specify specific configuration for certain protocols. Nowadays we only support Kafka specific information to define a Key form Messages as you can find [here](). -When a binding is specified in a message we will generate a generic class named as MessageWrapper which will contain the payload and the key used in to build a Message. +Asyncapi support a way to specify specific configuration for certain protocols. + +Nowadays, we only support Kafka specific information to define a Key form. + +Messages as you can find +[here](). + +When a binding is specified in a message we will generate a generic class +named as MessageWrapper which will contain the payload and the key +used in to build a Message. You will find such class by each api package you define. ##### Mapper @@ -584,7 +628,7 @@ file. Here is an example of a basic configuration: com.sngular scs-multiapi-maven-plugin - 5.4.2 + 5.4.3 @@ -664,9 +708,14 @@ openapimodel { specFile { { filePath = './src/main/resources/api/api.yml' - apiPackage = 'com.sngular.apigenerator.openapi.api' - modelPackage = 'com.sngular.apigenerator.openapi.api.model' - useTagsGroup = true + consumer { + apiPackage = 'com.sngular.apigenerator.openapi.api' + modelPackage = 'com.sngular.apigenerator.openapi.api.model' + } + supplier { + apiPackage = 'com.sngular.apigenerator.openapi.api' + modelPackage = 'com.sngular.apigenerator.openapi.api.model' + } } overWriteModel = true } diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml index 4f8ed86b..402bc19f 100644 --- a/multiapi-engine/pom.xml +++ b/multiapi-engine/pom.xml @@ -4,7 +4,7 @@ com.sngular multiapi-engine - 5.4.2 + 5.4.3 jar @@ -20,7 +20,7 @@ 5.9.2 2.2.9 3.0.0 - UTF-8 + diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGenerator.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGenerator.java index a766b61e..e64d4777 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGenerator.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGenerator.java @@ -154,7 +154,7 @@ public final void processFileSpec(final List specsListFile) { final ObjectMapper om = new ObjectMapper(new YAMLFactory()); processedOperationIds.clear(); generateExceptionTemplate = false; - for (SpecFile fileParameter : specsListFile) { + for (final SpecFile fileParameter : specsListFile) { final Pair ymlFileAndPath; try { ymlFileAndPath = resolveYmlLocation(fileParameter.getFilePath()); @@ -471,7 +471,7 @@ private void fillTemplateFactory( final JsonNode schemaToBuild = processedMethod.getPayload(); if (shouldBuild(schemaToBuild)) { final var schemaObjectIt = - MapperContentUtil.mapComponentToSchemaObject(totalSchemas, className, schemaToBuild, null, operationObject.getModelNameSuffix(), parentPackage, + MapperContentUtil.mapComponentToSchemaObject(totalSchemas, className, schemaToBuild, null, operationObject.getModelNameSuffix(), parentPackage, modelPackage, operationObject.getFormats(), operationObject.getUseTimeType()).iterator(); if (schemaObjectIt.hasNext()) { diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/util/MapperContentUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/util/MapperContentUtil.java index 87e446e7..1533b615 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/util/MapperContentUtil.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/asyncapi/util/MapperContentUtil.java @@ -6,7 +6,9 @@ package com.sngular.api.generator.plugin.asyncapi.util; + import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -64,19 +66,19 @@ private MapperContentUtil() {} public static List mapComponentToSchemaObject( final Map totalSchemas, final String component, final JsonNode model, final String prefix, final String suffix, final String parentPackage, - final Map formats, final TimeType useTimeType) { + final String modelPackage, final Map formats, final TimeType useTimeType) { final List schemasList = new ArrayList<>(); if (Objects.nonNull(model)) { final Queue modelToBuildList = new ConcurrentLinkedQueue<>(); final List alreadyBuilt = new ArrayList<>(); - schemasList.add(buildSchemaObject(totalSchemas, component, model, prefix, suffix, modelToBuildList, parentPackage, formats, useTimeType)); + schemasList.add(buildSchemaObject(totalSchemas, component, model, prefix, suffix, modelToBuildList, parentPackage, modelPackage, formats, useTimeType)); while (!modelToBuildList.isEmpty()) { final var modelToBuild = modelToBuildList.remove(); if (!alreadyBuilt.contains(modelToBuild)) { final var path = MapperUtil.splitName(modelToBuild); final var nexElement = buildSchemaObject(totalSchemas, modelToBuild, totalSchemas.get(getComponent(path)), - prefix, suffix, modelToBuildList, getParentName(path), formats, useTimeType); + prefix, suffix, modelToBuildList, getParentName(path), modelPackage, formats, useTimeType); if (schemasList.contains(nexElement)) { modelToBuildList.poll(); } else { @@ -92,7 +94,7 @@ public static List mapComponentToSchemaObject( private static String getParentName(final String[] path) { final String parenName; if (path.length > 1) { - parenName = path[path.length - 2]; + parenName = String.join(".", Arrays.copyOf(path, path.length - 1)); } else { parenName = ""; } @@ -100,6 +102,16 @@ private static String getParentName(final String[] path) { } private static String getComponent(final String[] path) { + final String componentName; + if (path.length > 1) { + componentName = String.join(".", Arrays.copyOf(path, path.length - 1)) + "/" + path[path.length - 1]; + } else { + componentName = path[0]; + } + return componentName.toUpperCase(); + } + + private static String getSchema(final String[] path) { final String componentName; if (path.length > 1) { componentName = path[path.length - 2] + "/" + path[path.length - 1]; @@ -112,9 +124,9 @@ private static String getComponent(final String[] path) { private static SchemaObject buildSchemaObject( final Map totalSchemas, final String component, final JsonNode model, final String prefix, final String suffix, final Collection modelToBuildList, final String parentPackage, - final Map formats, final TimeType useTimeType) { + final String modelPackage, final Map formats, final TimeType useTimeType) { - final var listSchema = getFields(totalSchemas, model, true, prefix, suffix, modelToBuildList, parentPackage, formats, useTimeType); + final var listSchema = getFields(totalSchemas, model, true, prefix, suffix, modelToBuildList, modelPackage, formats, useTimeType); final var splitPackage = MapperUtil.splitName(component); final String className = splitPackage[splitPackage.length - 1]; return SchemaObject.builder() @@ -130,7 +142,7 @@ private static SchemaObject buildSchemaObject( private static List getImportList(final List schemaListToImport) { final var importList = new HashSet(); - for (SchemaFieldObject fieldObject : schemaListToImport) { + for (final SchemaFieldObject fieldObject : schemaListToImport) { importList.addAll(getTypeImports(fieldObject)); } return new ArrayList<>(importList); @@ -168,31 +180,31 @@ private static List getTypeImports(final SchemaFieldObject fieldObject) private static List getFields( final Map totalSchemas, final JsonNode model, final boolean required, final String prefix, - final String suffix, final Collection modelToBuildList, final String parentPackage, - final Map formats, final TimeType useTimeType) { + final String suffix, final Collection modelToBuildList, + final String modelPackage, final Map formats, final TimeType useTimeType) { final var fieldObjectArrayList = new ArrayList(); schemaCombinatorType = null; if (ApiTool.hasType(model)) { if (OBJECT.equalsIgnoreCase(model.get(TYPE).textValue())) { - fieldObjectArrayList.addAll(processFieldObject(totalSchemas, model, prefix, suffix, modelToBuildList, parentPackage, formats, useTimeType)); + fieldObjectArrayList.addAll(processFieldObject(totalSchemas, model, prefix, suffix, modelToBuildList, modelPackage, formats, useTimeType)); } else if (ARRAY.equalsIgnoreCase(model.get(TYPE).textValue())) { - fieldObjectArrayList.add(processFieldObjectList(totalSchemas, "", model, required, prefix, suffix, modelToBuildList, parentPackage, null, formats, useTimeType)); + fieldObjectArrayList.add(processFieldObjectList(totalSchemas, "", model, required, prefix, suffix, modelToBuildList, modelPackage, null, formats, useTimeType)); } else if ("enum".equalsIgnoreCase(model.get(TYPE).textValue())) { - fieldObjectArrayList.add(processFieldObjectList(totalSchemas, "", model, required, prefix, suffix, modelToBuildList, parentPackage, null, formats, useTimeType)); + fieldObjectArrayList.add(processFieldObjectList(totalSchemas, "", model, required, prefix, suffix, modelToBuildList, modelPackage, null, formats, useTimeType)); } } else if (ApiTool.hasRef(model)) { final var splitName = MapperUtil.splitName(ApiTool.getRefValue(model)); fieldObjectArrayList.addAll(processFieldObject(totalSchemas, totalSchemas.get(MapperUtil.buildKey(splitName)), prefix, suffix, - modelToBuildList, parentPackage, formats, useTimeType)); + modelToBuildList, modelPackage, formats, useTimeType)); } else if (model.elements().hasNext()) { - fieldObjectArrayList.addAll(processFieldObject(totalSchemas, model, prefix, suffix, modelToBuildList, parentPackage, formats, useTimeType)); + fieldObjectArrayList.addAll(processFieldObject(totalSchemas, model, prefix, suffix, modelToBuildList, modelPackage, formats, useTimeType)); } return fieldObjectArrayList; } private static List processFieldObject( final Map totalSchemas, final JsonNode model, final String prefix, final String suffix, final Collection modelToBuildList, - final String parentPackage, final Map formats, final TimeType useTimeType) { + final String modelPackage, final Map formats, final TimeType useTimeType) { final Set requiredSet = new HashSet<>(); final var fieldObjectArrayList = new ArrayList(); if (model.has("required")) { @@ -206,8 +218,8 @@ private static List processFieldObject( while (propertiesIt.hasNext()) { final var property = propertiesIt.next(); fieldObjectArrayList.add(processFieldObjectList(totalSchemas, property, model.get(PROPERTIES).path(property), requiredSet.contains(property), prefix, suffix, - modelToBuildList, parentPackage, null, formats, useTimeType)); - if (model.get(PROPERTIES).path(property).has(REF) && !totalSchemas.containsKey(createKey(parentPackage, property.toUpperCase(), "/"))) { + modelToBuildList, modelPackage, null, formats, useTimeType)); + if (model.get(PROPERTIES).path(property).has(REF) && !totalSchemas.containsKey(createKey(modelPackage, property.toUpperCase(), "/"))) { modelToBuildList.add(MapperUtil.getLongRefClass(model.get(PROPERTIES).path(property))); } } @@ -308,7 +320,7 @@ private static SchemaFieldObject processFieldObjectList( } } else if (ApiTool.hasRef(schema)) { final var splitName = MapperUtil.splitName(ApiTool.getRefValue(schema)); - final var solvedRef = totalSchemas.get(getComponent(splitName)); + final var solvedRef = totalSchemas.get(getSchema(splitName)); fieldObject = processFieldObjectList(totalSchemas, name, solvedRef, required, prefix, suffix, modelToBuildList, modelPackage, splitName[splitName.length - 1], formats, useTimeType); } else { 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 de1fcb7a..6a32c51f 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 @@ -66,8 +66,8 @@ private static List getSecurityRequirementList(final JsonNode securityNo public static List mapPathObjects(final SpecFile specFile, final Collection> path, final GlobalObject globalObject, final Path baseDir) { final List pathObjects = new ArrayList<>(); - for (var pathMap : path) { - for (var pathItem : pathMap.entrySet()) { + for (final var pathMap : path) { + for (final var pathItem : pathMap.entrySet()) { final PathObject pathObject = PathObject.builder() .pathName(pathItem.getKey()) .globalObject(globalObject) @@ -85,7 +85,7 @@ private static List mapOperationObject(final SpecFile specFile, final List operationIdList = new ArrayList<>(); final var pathNode = path.getValue(); final var pathParameters = new ArrayList(); - for (Iterator> it = pathNode.fields(); it.hasNext();) { + for (final Iterator> it = pathNode.fields(); it.hasNext();) { final var field = it.next(); switch (field.getKey()) { case "get": @@ -218,7 +218,7 @@ private static List mapParameterObjects( final GlobalObject globalObject, final Path baseDir) { final List parameterObjects = new ArrayList<>(); if (Objects.nonNull(parameters) && !parameters.isEmpty()) { - for (JsonNode parameter : parameters) { + for (final JsonNode parameter : parameters) { if (ApiTool.hasRef(parameter)) { final JsonNode refParameter = globalObject.getParameterNode(MapperUtil.getRefSchemaName(parameter)).orElseThrow(); parameterObjects.add(buildParameterObject(specFile, globalObject, refParameter, baseDir)); @@ -260,7 +260,7 @@ private static List buildParameterContent( final var content = ApiTool.getNode(parameter, CONTENT); final var parameterName = ApiTool.getName(parameter); final var parameterObjects = new ArrayList(); - for (Iterator it = content.elements(); it.hasNext();) { + for (final Iterator it = content.elements(); it.hasNext();) { final var contentType = it.next(); final String inlineParameter = INLINE_PARAMETER + safeCapitalize(contentClassName) + StringUtils.capitalize(parameterName); @@ -337,7 +337,7 @@ private static List mapContentObject( final Path baseDir) { final List contentObjects = new ArrayList<>(); if (Objects.nonNull(content)) { - for (Iterator it = content.fieldNames(); it.hasNext(); ) { + for (final Iterator it = content.fieldNames(); it.hasNext();) { final String mediaType = it.next(); final var schema = ApiTool.getNode(ApiTool.getNode(content, mediaType), SCHEMA); final String pojoName = preparePojoName(inlineObject, schema, specFile); diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorFixtures.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorFixtures.java index 69ba8db5..666e8a58 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorFixtures.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorFixtures.java @@ -229,7 +229,7 @@ public class AsyncApiGeneratorFixtures { .streamBridge(OperationParameterObject.builder() .apiPackage("com.sngular.scsplugin.withoutids.model.event.producer") .modelPackage("com.sngular.scsplugin.withoutids.model.event") - .modelNameSuffix("Mapper") + .modelNameSuffix("DTO") .build()) .build() ); @@ -382,6 +382,24 @@ public class AsyncApiGeneratorFixtures { .build() ); + static final List TEST_SUB_OBJECT_SAME_NAME = + List.of( + SpecFile.builder() + .filePath("src/test/resources/asyncapigenerator/testSubObjectSameName/event-api.yml") + .consumer( + OperationParameterObject.builder() + .ids("input") + .apiPackage("input.controller") + .modelPackage("input.model") + .build()) + .supplier( + OperationParameterObject.builder() + .ids("output") + .apiPackage("output.provider") + .modelPackage("output.model") + .build()) + .build()); + final static String TARGET = "target"; final static String GENERATED = "generated/"; @@ -457,8 +475,8 @@ private static Boolean commonTest( } if (CollectionUtils.isNotEmpty(expectedExceptionFiles)) { - Path pathToTargetException = pathToTarget.resolve(targetException); - File targetModelException = pathToTargetException.toFile(); + final Path pathToTargetException = pathToTarget.resolve(targetException); + final File targetModelException = pathToTargetException.toFile(); Assertions.assertThat(targetModelException).isNotEmptyDirectory(); TestUtils.validateFiles(expectedExceptionFiles, targetModelException); } @@ -627,7 +645,7 @@ static Function validateTestRareCharsGeneration() { modelTest(path, expectedModelSchemaFiles, DEFAULT_MODEL_SCHEMA_FOLDER); } - static Function validateCustomValidators(int springBootVersion) { + static Function validateCustomValidators(final int springBootVersion) { final String DEFAULT_CONSUMER_FOLDER = "generated/com/sngular/scsplugin/customvalidator/model/event/consumer"; final String DEFAULT_PRODUCER_FOLDER = "generated/com/sngular/scsplugin/customvalidator/model/event/producer"; @@ -687,7 +705,7 @@ static Function validateCustomValidators(int springBootVersion) { customValidatorTest(path, expectedValidatorFiles, DEFAULT_CUSTOM_VALIDATOR_FOLDER); } - private static String calculateJavaEEPackage(int springBootVersion) { + private static String calculateJavaEEPackage(final int springBootVersion) { if (3 <= springBootVersion) { return "jakarta/"; } else { @@ -1025,4 +1043,48 @@ static Function validateTestFileGenerationWithKafkaBindings() { modelTest(path, expectedModelSchemaFiles, DEFAULT_COMMON_FOLDER) && customValidatorTest(path, expectedValidatorFiles, DEFAULT_CUSTOM_VALIDATOR_FOLDER); } + + static Function validateTestSubObjectSameName() { + + final String DEFAULT_COMMON_FOLDER = "generated"; + + final String DEFAULT_CONSUMER_FOLDER = DEFAULT_COMMON_FOLDER + "/input/controller"; + + final String DEFAULT_CONSUMER_MODEL_FOLDER = DEFAULT_COMMON_FOLDER + "/input/model"; + + final String DEFAULT_PRODUCER_FOLDER = DEFAULT_COMMON_FOLDER + "/output/provider"; + + final String DEFAULT_PRODUCER_MODEL_FOLDER = DEFAULT_COMMON_FOLDER + "/output/model"; + + final String COMMON_PATH = "asyncapigenerator/testSubObjectSameName/"; + + final String ASSETS_PATH = COMMON_PATH + "assets/"; + + final List expectedConsumerFiles = + List.of( + ASSETS_PATH + "input/controller/IInput.java", + ASSETS_PATH + "input/controller/Subscriber.java"); + + final List expectedProducerFiles = + List.of( + ASSETS_PATH + "output/provider/IOutput.java", + ASSETS_PATH + "output/provider/Producer.java"); + + final List expectedConsumerModelSchemaFiles = + List.of(ASSETS_PATH + "input/model/Data.java", ASSETS_PATH + "input/model/Input.java"); + final List expectedProducerModelSchemaFiles = + List.of(ASSETS_PATH + "output/model/Data.java", ASSETS_PATH + "output/model/Output.java"); + + return (path) -> + commonTest( + path, + expectedConsumerFiles, + expectedProducerFiles, + DEFAULT_CONSUMER_FOLDER, + DEFAULT_PRODUCER_FOLDER, + Collections.emptyList(), + null) + && modelTest(path, expectedConsumerModelSchemaFiles, DEFAULT_CONSUMER_MODEL_FOLDER) + && modelTest(path, expectedProducerModelSchemaFiles, DEFAULT_PRODUCER_MODEL_FOLDER); + } } diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorTest.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorTest.java index 5ec114e6..a047c3ee 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorTest.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/asyncapi/AsyncApiGeneratorTest.java @@ -70,9 +70,9 @@ static Stream fileSpecToProcess() { Arguments.of("TestConstantGeneration", AsyncApiGeneratorFixtures.TEST_CONSTANT_GENERATION, AsyncApiGeneratorFixtures.validateConstantGeneration()), Arguments.of("testPropertiesNotGeneratedIssue", AsyncApiGeneratorFixtures.PROPERTIES_NOT_GENERATED_ISSUE, AsyncApiGeneratorFixtures.validateNotGeneratedPropertiesIssue()), Arguments.of("TestFileGenerationWithKafkaBindings", AsyncApiGeneratorFixtures.TEST_FILE_GENERATION_WITH_KAFKA_BINDINGS, - AsyncApiGeneratorFixtures.validateTestFileGenerationWithKafkaBindings()) - - ); + AsyncApiGeneratorFixtures.validateTestFileGenerationWithKafkaBindings()), + Arguments.of("TestSubObjectSameName", AsyncApiGeneratorFixtures.TEST_SUB_OBJECT_SAME_NAME, + AsyncApiGeneratorFixtures.validateTestSubObjectSameName())); } @ParameterizedTest(name = "Test {index} - Process File Spec for case {0}") 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 9097c333..564c9836 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 @@ -1160,6 +1160,7 @@ static Function validateCoconutSchema() { return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, expectedExceptionFiles, DEFAULT_EXCEPTION_API); } + static Function validateRestrictionsSchema() { final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testRestrictionsSchema"; @@ -1201,7 +1202,7 @@ static Function validateRestrictionsSchema() { return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, expectedExceptionFiles, DEFAULT_EXCEPTION_API); } -static Function validateSimpleBuild() { + static Function validateSimpleBuild() { final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testsimplebuild"; diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorJakartaTest.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorJakartaTest.java index 082722c8..174575a2 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorJakartaTest.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorJakartaTest.java @@ -28,7 +28,7 @@ class OpenApiGeneratorJakartaTest { private static OpenApiGenerator openApiGenerator; - private static int SPRING_BOOT_VERSION = 3; + private static final int SPRING_BOOT_VERSION = 3; @BeforeAll static void setup() { diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testFileGenerationWithoutOperationIds/assets/StreamBridgeProducer.java b/multiapi-engine/src/test/resources/asyncapigenerator/testFileGenerationWithoutOperationIds/assets/StreamBridgeProducer.java index 473ade6a..133949a6 100644 --- a/multiapi-engine/src/test/resources/asyncapigenerator/testFileGenerationWithoutOperationIds/assets/StreamBridgeProducer.java +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testFileGenerationWithoutOperationIds/assets/StreamBridgeProducer.java @@ -2,7 +2,7 @@ import org.springframework.stereotype.Component; import org.springframework.cloud.stream.function.StreamBridge; -import com.sngular.scsplugin.withoutids.model.event.OrderMapper; +import com.sngular.scsplugin.withoutids.model.event.OrderDTO; @Component public class StreamBridgeProducer { diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/IInput.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/IInput.java new file mode 100644 index 00000000..6773a585 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/IInput.java @@ -0,0 +1,8 @@ +package input.controller; + +import input.model.Input; + +public interface IInput { + + void input(final Input value); +} \ No newline at end of file diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/Subscriber.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/Subscriber.java new file mode 100644 index 00000000..e06d9840 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/controller/Subscriber.java @@ -0,0 +1,24 @@ +package input.controller; + +import java.util.function.Consumer; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import input.model.Input; + +@Configuration +public class Subscriber { + + private final IInput input; + + protected Subscriber(final IInput input) { + this.input = input; + } + + @Bean + public Consumer input() { + return value -> input.input(value); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Data.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Data.java new file mode 100644 index 00000000..b5b17bec --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Data.java @@ -0,0 +1,80 @@ +package input.model; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonDeserialize(builder = Data.DataBuilder.class) +public class Data { + + @JsonProperty(value ="commitId") + private String commitId; + + private Data(DataBuilder builder) { + this.commitId = builder.commitId; + + } + + public static Data.DataBuilder builder() { + return new Data.DataBuilder(); + } + + @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "") + public static class DataBuilder { + + private String commitId; + + public Data.DataBuilder commitId(String commitId) { + this.commitId = commitId; + return this; + } + + public Data build() { + Data data = new Data(this); + return data; + } + } + + /** + * Get commitId + * @return commitId + */ + @Schema(name = "commitId", required = false) + public String getCommitId() { + return commitId; + } + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Data data = (Data) o; + return Objects.equals(this.commitId, data.commitId); + } + + @Override + public int hashCode() { + return Objects.hash(commitId); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Data{"); + sb.append(" commitId:").append(commitId); + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Input.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Input.java new file mode 100644 index 00000000..10781348 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/input/model/Input.java @@ -0,0 +1,123 @@ +package input.model; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonDeserialize(builder = Input.InputBuilder.class) +public class Input { + + @JsonProperty(value ="source") + private Source source; + public enum Source { + INPUT("input"); + + private String value; + + Source(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + @JsonProperty(value ="data") + private Data data; + + private Input(InputBuilder builder) { + this.source = builder.source; + this.data = builder.data; + + } + + public static Input.InputBuilder builder() { + return new Input.InputBuilder(); + } + + @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "") + public static class InputBuilder { + + private Source source; + + private Data data; + + public Input.InputBuilder source(Source source) { + this.source = source; + return this; + } + + public Input.InputBuilder data(Data data) { + this.data = data; + return this; + } + + public Input build() { + Input input = new Input(this); + return input; + } + } + + /** + * Get source + * @return source + */ + @Schema(name = "source", required = false) + public Source getSource() { + return source; + } + public void setSource(Source source) { + this.source = source; + } + + /** + * Get data + * @return data + */ + @Schema(name = "data", required = false) + public Data getData() { + return data; + } + public void setData(Data data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Input input = (Input) o; + return Objects.equals(this.source, input.source) && Objects.equals(this.data, input.data); + } + + @Override + public int hashCode() { + return Objects.hash(source, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Input{"); + sb.append(" source:").append(source).append(","); + sb.append(" data:").append(data); + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Data.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Data.java new file mode 100644 index 00000000..74c81981 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Data.java @@ -0,0 +1,103 @@ +package output.model; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonDeserialize(builder = Data.DataBuilder.class) +public class Data { + + @JsonProperty(value ="tenantId") + private String tenantId; + @JsonProperty(value ="name") + private String name; + + private Data(DataBuilder builder) { + this.tenantId = builder.tenantId; + this.name = builder.name; + + } + + public static Data.DataBuilder builder() { + return new Data.DataBuilder(); + } + + @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "") + public static class DataBuilder { + + private String tenantId; + + private String name; + + public Data.DataBuilder tenantId(String tenantId) { + this.tenantId = tenantId; + return this; + } + + public Data.DataBuilder name(String name) { + this.name = name; + return this; + } + + public Data build() { + Data data = new Data(this); + return data; + } + } + + /** + * Get tenantId + * @return tenantId + */ + @Schema(name = "tenantId", required = false) + public String getTenantId() { + return tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + /** + * Get name + * @return name + */ + @Schema(name = "name", required = false) + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Data data = (Data) o; + return Objects.equals(this.tenantId, data.tenantId) && Objects.equals(this.name, data.name); + } + + @Override + public int hashCode() { + return Objects.hash(tenantId, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Data{"); + sb.append(" tenantId:").append(tenantId).append(","); + sb.append(" name:").append(name); + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Output.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Output.java new file mode 100644 index 00000000..cbbdbc88 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/model/Output.java @@ -0,0 +1,166 @@ +package output.model; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonDeserialize(builder = Output.OutputBuilder.class) +public class Output { + + @JsonProperty(value ="source") + private Source source; + public enum Source { + TENANT("tenant"); + + private String value; + + Source(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + @JsonProperty(value ="type") + private Type type; + public enum Type { + UPDATE("update"), + DELETE("delete"); + + private String value; + + Type(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + @JsonProperty(value ="data") + private Data data; + + private Output(OutputBuilder builder) { + this.source = builder.source; + this.type = builder.type; + this.data = builder.data; + + } + + public static Output.OutputBuilder builder() { + return new Output.OutputBuilder(); + } + + @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "") + public static class OutputBuilder { + + private Source source; + + private Type type; + + private Data data; + + public Output.OutputBuilder source(Source source) { + this.source = source; + return this; + } + + public Output.OutputBuilder type(Type type) { + this.type = type; + return this; + } + + public Output.OutputBuilder data(Data data) { + this.data = data; + return this; + } + + public Output build() { + Output output = new Output(this); + return output; + } + } + + /** + * Get source + * @return source + */ + @Schema(name = "source", required = false) + public Source getSource() { + return source; + } + public void setSource(Source source) { + this.source = source; + } + + /** + * Get type + * @return type + */ + @Schema(name = "type", required = false) + public Type getType() { + return type; + } + public void setType(Type type) { + this.type = type; + } + + /** + * Get data + * @return data + */ + @Schema(name = "data", required = false) + public Data getData() { + return data; + } + public void setData(Data data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Output output = (Output) o; + return Objects.equals(this.source, output.source) && Objects.equals(this.type, output.type) && Objects.equals(this.data, output.data); + } + + @Override + public int hashCode() { + return Objects.hash(source, type, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Output{"); + sb.append(" source:").append(source).append(","); + sb.append(" type:").append(type).append(","); + sb.append(" data:").append(data); + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/IOutput.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/IOutput.java new file mode 100644 index 00000000..7882d3e1 --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/IOutput.java @@ -0,0 +1,8 @@ +package output.provider; + +import output.model.Output; + +public interface IOutput { + + Output output(); +} \ No newline at end of file diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/Producer.java b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/Producer.java new file mode 100644 index 00000000..cca7247b --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/assets/output/provider/Producer.java @@ -0,0 +1,24 @@ +package output.provider; + +import java.util.function.Supplier; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import output.model.Output; + +@Configuration +public class Producer { + + private final IOutput output; + + protected Producer(final IOutput output) { + this.output = output; + } + + @Bean + public Supplier output() { + return () -> output.output(); + } + + +} diff --git a/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/event-api.yml b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/event-api.yml new file mode 100644 index 00000000..8bdd407d --- /dev/null +++ b/multiapi-engine/src/test/resources/asyncapigenerator/testSubObjectSameName/event-api.yml @@ -0,0 +1,98 @@ +asyncapi: 2.5.0 +info: + title: Component MQTT interface contract + version: '1.0.0' + description: | + This document describe the input and output of the component + +defaultContentType: application/json +channels: + events/public/output/{organizationId}: + description: The output topic + parameters: + organizationId: + $ref: '#/components/parameters/organizationId' + subscribe: + operationId: output + traits: + - bindings: + mqtt: + retain: true + message: + $ref: '#/components/messages/output' + events/public/input/{organizationId}: + description: The input topic + parameters: + organizationId: + $ref: '#/components/parameters/organizationId' + publish: + operationId: input + traits: + - bindings: + mqtt: + retain: true + message: + $ref: '#/components/messages/input' +components: + messages: + output: + name: output + title: Output message + summary: bob + contentType: application/json + payload: + $ref: "#/components/schemas/output" + input: + name: inputmsg + title: input message + summary: eve + contentType: application/json + payload: + $ref: "#/components/schemas/input" + schemas: + input: + type: object + properties: + source: + type: string + enum: + - "input" + data: # DATA Object first definition + type: object + properties: + commitId: + type: string + examples: + - "toto" + - "tata" + output: + type: object + properties: + source: + type: string + enum: + - "tenant" + type: + type: string + enum: + - "update" + - "delete" + data: # DATA object second definition + type: object + properties: + tenantId: + type: string + examples: + - tenant1 + name: + type: string + examples: + - "hugues" + parameters: + organizationId: + description: The identifier of an organization + schema: + type: string + examples: + - "toto" + - "bob" \ No newline at end of file diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle index cbbb8b4a..351cdd7d 100644 --- a/scs-multiapi-gradle-plugin/build.gradle +++ b/scs-multiapi-gradle-plugin/build.gradle @@ -20,7 +20,7 @@ repositories { } group = 'com.sngular' -version = '5.4.2' +version = '5.4.3' def SCSMultiApiPluginGroupId = group def SCSMultiApiPluginVersion = version @@ -30,7 +30,7 @@ dependencies { shadow localGroovy() shadow gradleApi() - implementation 'com.sngular:multiapi-engine:5.4.2' + implementation 'com.sngular:multiapi-engine:5.4.3' testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'com.puppycrawl.tools:checkstyle:10.12.3' } @@ -98,7 +98,7 @@ testing { integrationTest(JvmTestSuite) { dependencies { - implementation 'com.sngular:scs-multiapi-gradle-plugin:5.4.2' + implementation 'com.sngular:scs-multiapi-gradle-plugin:5.4.3' 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 3c60dc4a..0df6bc3c 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 - 5.4.2 + 5.4.3 maven-plugin AsyncApi - OpenApi Code Generator Maven Plugin @@ -271,7 +271,7 @@ com.sngular multiapi-engine - 5.4.2 + 5.4.3 org.apache.maven @@ -438,7 +438,8 @@ junit.jupiter.execution.parallel.mode.default=concurrent junit.jupiter.execution.parallel.mode.classes.default=same_thread junit.jupiter.execution.parallel.config.strategy=fixed - junit.jupiter.execution.parallel.config.fixed.parallelism=6 + junit.jupiter.execution.parallel.config.fixed.parallelism=6 + diff --git a/styles/OSS_style_idea.xml b/styles/OSS_style_idea.xml index 8cb64cb0..9b42a81d 100644 --- a/styles/OSS_style_idea.xml +++ b/styles/OSS_style_idea.xml @@ -1,4 +1,4 @@ - + - + @@ -33,13 +33,18 @@