diff --git a/.github/workflows/maven-central-push.yml b/.github/workflows/maven-central-push.yml index 464af80d..e7264976 100644 --- a/.github/workflows/maven-central-push.yml +++ b/.github/workflows/maven-central-push.yml @@ -71,7 +71,7 @@ jobs: # Uses production profile to sign with gpg plugin run: | cd scs-multiapi-maven-plugin - mvn deploy -P production + mvn deploy -DskipLocalStaging=true -P production --file pom.xml env: MAVEN_USERNAME: ${{ secrets.JIRAID }} MAVEN_CENTRAL_TOKEN: ${{ secrets.JIRAPASS }} diff --git a/.github/workflows/update-wiki.yml b/.github/workflows/update-wiki.yml index 2665d943..90125fb8 100644 --- a/.github/workflows/update-wiki.yml +++ b/.github/workflows/update-wiki.yml @@ -55,4 +55,4 @@ jobs: git add . git commit -m "scs-multiapi-plugin documentation | GitHub Actions $GITHUB_WORKFLOW $GITHUB_RUN_NUMBER" git remote add origin-wiki "https://${{secrets.GITBOT_TOKEN}}@github.com/sngular/scs-multiapi-plugin.wiki.git" - git push origin-wiki master + git push origin-wiki main diff --git a/README.md b/README.md index 6f9e98e0..803402fa 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ Maven and Gradle - [AsyncApi Generator](#asyncapi-generator) - [Configuration](#configuration) - [Generated Sources Folder](#generated-sources-folder) - - [How apiPackage is setted?](#how-apipackage-is-setted) - - [How modelPackage is setted?](#how-modelpackage-is-setted) + - [How is apiPackage set?](#how-is-apipackage-set) + - [How is modelPackage set?](#how-is-modelpackage-set) - [Class Generation](#class-generation) - [Consumer and Supplier classes](#consumer-and-supplier-classes) - [Method interfaces](#method-interfaces) @@ -216,8 +216,8 @@ YML files as you want. **filePath** parameter, that expects to receive the path to the file. Using the plugin in this way, you can't configure the model package or the api package in the pom file, neither other options, so they will be configured as - its explained in [apiPackage](#how-apipackage-is-setted) and - [modelPackage](#how-modelpackage-is-setted) sections. + its explained in [apiPackage](#how-is-apipackage-set) and + [modelPackage](#how-is-modelpackage-set) sections. This way it's limited to the usage of Consumer and Supplier methods. ```xml @@ -301,7 +301,7 @@ can be configured in the plugin. result as `EntityClassDTO`. This parameter is optional. - **apiPackage**: This parameter receive a package name, where the generated classes will be generated. This parameter is optional. - Check [how the apiPackage is setted](#how-apipackage-is-setted) for + Check [how is the apiPackage set](#how-is-apipackage-set) for more information about how this parameter works, and the values it could have. - **modelPackage**: This parameter receives a package name, where the entities @@ -311,7 +311,7 @@ can be configured in the plugin. **Note that the plugin doesn't create the entities neither checks their existence**, it takes their names from the YML file and assume that they are created by the user. As the previous parameter, this is also optional. - Check [how the modelPackage is setted](#how-modelpackage-is-setted) for more + Check [how is the modelPackage set](#how-is-modelpackage-set) for more information about how his parameter works, and the values it could have. The configuration of `consumer`, `supplier` and `streamBridge` are independent. @@ -330,7 +330,7 @@ By default, it's values is `generated-sources`, so the files will be in the pom.xml file, as in the example above, files will remain in `.../target/sources-generated/apigenerator/...`. -### How apiPackage is setted? +### How is apiPackage set? The api package could be set in three different ways. @@ -342,7 +342,7 @@ The api package could be set in three different ways. plugin will use a default package name, that is stablished as `com.sngular.apigenerator.asyncapi`. -### How modelPackage is setted? +### How is modelPackage set? The model package could be set in four different ways. @@ -666,14 +666,15 @@ that will be used. Each specFile has their own configuration: | Name | Description | Example | |--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------| | filePath | Path where the yaml is located | ${project.basedir}/src/main/resources/api/api.yml | -| apiPackage | Path where the api interface will be located | com.sngular.apigenerator.openapi | -| modelPackage | Path where the models will be located | com.sngular.apigenerator.openapi.model | +| apiPackage | Path where the api interface will be located | com.sngular.apigenerator.openapi | +| modelPackage | Path where the models will be located | com.sngular.apigenerator.openapi.model | | modelNamePrefix | Prefix that will be used ahead of every model´s name | Api | | modelNameSuffix | Suffix that will be used after every model´s name | DTO | | callMode | Boolean value to decide if you want to generate the api for external calls. **Use RestClient by default. It´s initialized to false by default** | false | | useTagsGroup | Boolean value to decide if using tags instead of an URL for group the API. **It´s initialized to false by default** | false | | useLombokModelAnnotation | Boolean value to decide if you want your models with Lombok or not **It´s initialized to false by default** | false | | isReactive | Boolean value to decide if you want to generate the api with responses in Mono/Flux Reactor types. If callmode = true use WebClient instead of RestClient. **It´s initialized to false by default** | false | +| useTimeType | Enum TimeType value. Controls the types used when generating dates. Can be local, zoned, or offset. **Initialized to TimeType.LOCAL by default** | TimeType.OFFSET | As the configuration options already indicate, the data model will also be created within the specified path.This model will be created with the indicated diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml index f8ff315f..93bf5ef8 100644 --- a/multiapi-engine/pom.xml +++ b/multiapi-engine/pom.xml @@ -4,7 +4,7 @@ com.sngular multiapi-engine - 4.5.2 + 4.6.1 jar @@ -241,6 +241,7 @@ com.github.ekryd.sortpom sortpom-maven-plugin + 3.2.1 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 11b8eac9..3b6125c9 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 @@ -323,41 +323,42 @@ private static void handleItems(final JsonNode schema, final Collection private static void setFieldProperties(final SchemaFieldObject fieldObject, final JsonNode schema) { final Iterator> iterator = schema.fields(); Entry current; + final SchemaFieldObjectProperties props = fieldObject.getRestrictions(); while (iterator.hasNext()) { current = iterator.next(); switch (current.getKey()) { case "minimum": - fieldObject.getRestrictions().setMinimum(current.getValue().asText()); + props.setMinimum(current.getValue().asText()); break; case "maximum": - fieldObject.getRestrictions().setMaximum(current.getValue().asText()); + props.setMaximum(current.getValue().asText()); break; case "exclusiveMinimum": - fieldObject.getRestrictions().setExclusiveMinimum(current.getValue().booleanValue()); + props.setExclusiveMinimum(current.getValue().booleanValue()); break; case "exclusiveMaximum": - fieldObject.getRestrictions().setExclusiveMaximum(current.getValue().booleanValue()); + props.setExclusiveMaximum(current.getValue().booleanValue()); break; case "maxItems": - fieldObject.getRestrictions().setMaxItems(current.getValue().intValue()); + props.setMaxItems(current.getValue().intValue()); break; case "maxLength": - fieldObject.getRestrictions().setMaxLength(current.getValue().intValue()); + props.setMaxLength(current.getValue().intValue()); break; case "minItems": - fieldObject.getRestrictions().setMinItems(current.getValue().intValue()); + props.setMinItems(current.getValue().intValue()); break; case "minLength": - fieldObject.getRestrictions().setMinLength(current.getValue().intValue()); + props.setMinLength(current.getValue().intValue()); break; case "pattern": - fieldObject.getRestrictions().setPattern(current.getValue().toString().replaceAll("\"", "")); + props.setPattern(current.getValue().toString().replaceAll("\"", "")); break; case "uniqueItems": - fieldObject.getRestrictions().setUniqueItems(current.getValue().booleanValue()); + props.setUniqueItems(current.getValue().booleanValue()); break; case "multipleOf": - fieldObject.getRestrictions().setMultipleOf(current.getValue().asText()); + props.setMultipleOf(current.getValue().asText()); break; default: break; diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/OpenApiGenerator.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/OpenApiGenerator.java index 229e3708..faa972fa 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/OpenApiGenerator.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/OpenApiGenerator.java @@ -107,7 +107,6 @@ public class OpenApiGenerator { private boolean useLombok; - public OpenApiGenerator(final Boolean overwriteModel, final String processedGeneratedSourcesFolder, final String groupId, final File targetFolder, final File basedir) { templateFactory = new TemplateFactory(); this.overwriteModel = overwriteModel; diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/BasicTypeConstants.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/BasicTypeConstants.java deleted file mode 100644 index ae12b05c..00000000 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/BasicTypeConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * * License, v. 2.0. If a copy of the MPL was not distributed with this - * * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package com.sngular.api.generator.plugin.openapi.model; - -import java.util.Set; - -public final class BasicTypeConstants { - - public static final String NUMBER = "number"; - - public static final String STRING = "string"; - - public static final String BOOLEAN = "boolean"; - - public static final String INTEGER = "integer"; - - public static final String ARRAY = "array"; - - public static final Set BASIC_OBJECT_TYPE = Set.of(NUMBER, STRING, BOOLEAN, INTEGER, ARRAY); - - private BasicTypeConstants() { - - } - -} diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObject.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObject.java index 2a74c9f8..4319287e 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObject.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObject.java @@ -15,8 +15,6 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.OBJECT; - @Data @Builder @NoArgsConstructor @@ -27,8 +25,9 @@ public class SchemaFieldObject { private String baseName; @Default - private SchemaFieldObjectType dataType = new SchemaFieldObjectType(OBJECT); + private SchemaFieldObjectType dataType = new SchemaFieldObjectType(TypeConstants.OBJECT); + @Default private SchemaFieldObjectProperties restrictionProperties = new SchemaFieldObjectProperties(); private String importClass; diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObjectType.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObjectType.java index b13ac3c1..989f32cb 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObjectType.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/SchemaFieldObjectType.java @@ -1,140 +1,137 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + package com.sngular.api.generator.plugin.openapi.model; -import java.util.Arrays; -import java.util.Iterator; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Map; import java.util.Objects; -import java.util.Set; import lombok.Data; @Data public class SchemaFieldObjectType { - public static final String OBJECT = "Object"; - - public static final String ARRAY = "Array"; - - public static final String MAP = "Map"; - - public static final String BIG_DECIMAL = "BigDecimal"; - - public static final String INTEGER = "Integer"; - - public static final String DOUBLE = "Double"; - - public static final String FLOAT = "Float"; - - public static final String LONG = "Long"; - - public static final String STRING = "String"; - - public static final String ENUM = "enum"; - - public static final Set BASIC_TYPES = Set.of(STRING, INTEGER, OBJECT); - - private static final Map typeMappings = Map.of( - OBJECT, "Object", - ARRAY, "List", - MAP, "Map", - BIG_DECIMAL, "BigDecimal", - INTEGER, "Integer", - DOUBLE, "Double", - FLOAT, "Float", - LONG, "Long", - STRING, "String", - ENUM, "Enum" + private static final Map TYPE_MAPPINGS = Map.ofEntries( + new SimpleImmutableEntry<>(TypeConstants.OBJECT, "Object"), + new SimpleImmutableEntry<>(TypeConstants.ARRAY, "List"), + new SimpleImmutableEntry<>(TypeConstants.MAP, "Map"), + new SimpleImmutableEntry<>(TypeConstants.BIG_DECIMAL, "BigDecimal"), + new SimpleImmutableEntry<>(TypeConstants.INTEGER, "Integer"), + new SimpleImmutableEntry<>(TypeConstants.DOUBLE, "Double"), + new SimpleImmutableEntry<>(TypeConstants.FLOAT, "Float"), + new SimpleImmutableEntry<>(TypeConstants.LONG, "Long"), + new SimpleImmutableEntry<>(TypeConstants.STRING, "String"), + new SimpleImmutableEntry<>(TypeConstants.ENUM, "Enum"), + new SimpleImmutableEntry<>(TypeConstants.LOCALDATE, "LocalDate"), + new SimpleImmutableEntry<>(TypeConstants.LOCALDATETIME, "LocalDateTime"), + new SimpleImmutableEntry<>(TypeConstants.ZONEDDATE, "ZonedDateTime"), + new SimpleImmutableEntry<>(TypeConstants.ZONEDDATETIME, "ZonedDateTime"), + new SimpleImmutableEntry<>(TypeConstants.OFFSETDATE, "OffsetDateTime"), + new SimpleImmutableEntry<>(TypeConstants.OFFSETDATETIME, "OffsetDateTime") ); - private static final Map implTypeMappings = Map.of( - OBJECT, "Object", - ARRAY, "ArrayList", - MAP, "HashMap", - BIG_DECIMAL, "BigDecimal", - INTEGER, "Integer", - DOUBLE, "Double", - FLOAT, "Float", - LONG, "Long", - STRING, "String", - ENUM, "Enum" + private static final Map IMPL_TYPE_MAPPINGS = Map.ofEntries( + new SimpleImmutableEntry<>(TypeConstants.OBJECT, "Object"), + new SimpleImmutableEntry<>(TypeConstants.ARRAY, "ArrayList"), + new SimpleImmutableEntry<>(TypeConstants.MAP, "HashMap"), + new SimpleImmutableEntry<>(TypeConstants.BIG_DECIMAL, "BigDecimal"), + new SimpleImmutableEntry<>(TypeConstants.INTEGER, "Integer"), + new SimpleImmutableEntry<>(TypeConstants.DOUBLE, "Double"), + new SimpleImmutableEntry<>(TypeConstants.FLOAT, "Float"), + new SimpleImmutableEntry<>(TypeConstants.LONG, "Long"), + new SimpleImmutableEntry<>(TypeConstants.STRING, "String"), + new SimpleImmutableEntry<>(TypeConstants.ENUM, "Enum"), + new SimpleImmutableEntry<>(TypeConstants.LOCALDATE, "LocalDate"), + new SimpleImmutableEntry<>(TypeConstants.LOCALDATETIME, "LocalDateTime"), + new SimpleImmutableEntry<>(TypeConstants.ZONEDDATE, "ZonedDateTime"), + new SimpleImmutableEntry<>(TypeConstants.ZONEDDATETIME, "ZonedDateTime"), + new SimpleImmutableEntry<>(TypeConstants.OFFSETDATE, "OffsetDateTime"), + new SimpleImmutableEntry<>(TypeConstants.OFFSETDATETIME, "OffsetDateTime") ); private SchemaFieldObjectType innerType; private final String baseType; - public SchemaFieldObjectType(String baseType, SchemaFieldObjectType innerType) { + public SchemaFieldObjectType(final String baseType, final SchemaFieldObjectType innerType) { this.innerType = innerType; this.baseType = baseType; } - public SchemaFieldObjectType(String type) { + public SchemaFieldObjectType(final String type) { this.innerType = null; this.baseType = type; } - public static SchemaFieldObjectType fromTypeList(String... types) { - Iterator typeIterator = Arrays.stream(types).iterator(); - return constructTypeFromList(typeIterator); - } + public static SchemaFieldObjectType fromTypeList(final String... types) { + final SchemaFieldObjectType result = new SchemaFieldObjectType(types[0], null); + SchemaFieldObjectType objectType = result; - private static SchemaFieldObjectType constructTypeFromList(Iterator types) { - if (!types.hasNext()) { - return null; + for (int i = 1; i < types.length; i++) { + objectType.innerType = new SchemaFieldObjectType(types[i], null); + objectType = objectType.innerType; } - return new SchemaFieldObjectType(types.next(), constructTypeFromList(types)); + return result; } - public void setDeepType(SchemaFieldObjectType type) { - if (Objects.isNull(innerType)) { - innerType = type; - return; + public void setDeepType(final SchemaFieldObjectType type) { + SchemaFieldObjectType parentType = this; + while (Objects.nonNull(parentType.innerType)) { + parentType = parentType.innerType; } - innerType.setDeepType(type); + parentType.innerType = type; } - public void setDeepType(String type) { + public void setDeepType(final String type) { setDeepType(new SchemaFieldObjectType(type)); } - public boolean containsType(String type) { - return type.equals(baseType) || (Objects.nonNull(innerType) && innerType.containsType(type)); + public boolean containsType(final String type) { + return type.equalsIgnoreCase(baseType) || Objects.nonNull(innerType) && innerType.containsType(type); } - private String mapIntoString(Map mappings) { - String baseString = mappings.getOrDefault(baseType, baseType); - if (!baseString.contains("?")) { - return baseString; - } + private String mapIntoString(final Map mappings) { + final String baseString = mappings.getOrDefault(baseType, baseType); + final boolean hasInner = baseString.contains("?"); - if (Objects.isNull(innerType)) { + if (hasInner && Objects.isNull(innerType)) { throw new RuntimeException(String.format("Field object type '%s' missing an inner type", baseType)); } - return baseString.replace("?", innerType.mapIntoString(typeMappings)); + return hasInner ? baseString.replace("?", innerType.mapIntoString(TYPE_MAPPINGS)) : baseString; } + @SuppressWarnings("unused") // This method is invoked by templates public String getImplementationTypeString() { - return mapIntoString(implTypeMappings); + return mapIntoString(IMPL_TYPE_MAPPINGS); } @Override public String toString() { - return mapIntoString(typeMappings); + return mapIntoString(TYPE_MAPPINGS); } @Override public boolean equals(final Object obj) { - if (!(obj instanceof SchemaFieldObjectType)) { - return false; + boolean result = false; + if (obj instanceof SchemaFieldObjectType) { + final SchemaFieldObjectType other = (SchemaFieldObjectType) obj; + final boolean baseTypeIsEqual = baseType.equals(other.baseType); + final boolean innerTypeIsEqual = Objects.isNull(innerType) ? Objects.isNull(other.innerType) : innerType.equals(other.innerType); + result = baseTypeIsEqual && innerTypeIsEqual; } - SchemaFieldObjectType other = (SchemaFieldObjectType) obj; - final boolean baseTypeIsEqual = baseType.equals(other.baseType); - final boolean innerTypeIsEqual = Objects.isNull(innerType) ? Objects.isNull(other.innerType) : innerType.equals(other.innerType); + return result; + } - return baseTypeIsEqual && innerTypeIsEqual; + @Override + public int hashCode() { + return Objects.hash(Objects.isNull(innerType) ? 0 : innerType.hashCode(), baseType); } } diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/TypeConstants.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/TypeConstants.java new file mode 100644 index 00000000..e8fba9c3 --- /dev/null +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/model/TypeConstants.java @@ -0,0 +1,65 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package com.sngular.api.generator.plugin.openapi.model; + +import java.util.Set; + +public final class TypeConstants { + + public static final String NUMBER = "number"; + + public static final String BOOLEAN = "boolean"; + + public static final String OBJECT = "object"; + + public static final String ARRAY = "array"; + + public static final String MAP = "map"; + + public static final String BIG_DECIMAL = "bigDecimal"; + + public static final String INTEGER = "integer"; + + public static final String DOUBLE = "double"; + + public static final String FLOAT = "float"; + + public static final String LONG = "long"; + + public static final String STRING = "string"; + + public static final String ENUM = "enum"; + + public static final String LOCALDATE = "localdate"; + + public static final String LOCALDATETIME = "localdatetime"; + + public static final String ZONEDDATE = "zoneddate"; + + public static final String ZONEDDATETIME = "zoneddatetime"; + + public static final String OFFSETDATE = "offsetdate"; + + public static final String OFFSETDATETIME = "offsetdatetime"; + + public static final String INT_32 = "int32"; + + public static final String INT_64 = "int64"; + + 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); + + public enum TimeType { + LOCAL, ZONED, OFFSET + } + + private TypeConstants() { + + } + +} diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/parameter/SpecFile.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/parameter/SpecFile.java index ba595f38..1db5ea54 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/parameter/SpecFile.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/parameter/SpecFile.java @@ -6,8 +6,10 @@ package com.sngular.api.generator.plugin.openapi.parameter; +import com.sngular.api.generator.plugin.openapi.model.TypeConstants.TimeType; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; @@ -36,4 +38,7 @@ public class SpecFile { private boolean useLombokModelAnnotation; private boolean isReactive; + + @Default + private TimeType useTimeType = TimeType.LOCAL; } diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperContentUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperContentUtil.java index 4773b2c5..3fd0200c 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperContentUtil.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperContentUtil.java @@ -6,30 +6,13 @@ package com.sngular.api.generator.plugin.openapi.utils; -import static com.sngular.api.generator.plugin.commonApi.Constants.ADDITIONAL_PROPERTIES; -import static com.sngular.api.generator.plugin.commonApi.Constants.ENUM; -import static com.sngular.api.generator.plugin.commonApi.Constants.ITEMS; -import static com.sngular.api.generator.plugin.commonApi.Constants.NAME; -import static com.sngular.api.generator.plugin.commonApi.Constants.PROPERTIES; -import static com.sngular.api.generator.plugin.commonApi.Constants.REF; -import static com.sngular.api.generator.plugin.commonApi.Constants.REQUIRED; -import static com.sngular.api.generator.plugin.commonApi.Constants.SLASH; -import static com.sngular.api.generator.plugin.commonApi.Constants.TYPE; -import static com.sngular.api.generator.plugin.commonApi.Constants.UNION; +import static com.sngular.api.generator.plugin.commonApi.Constants; import static com.sngular.api.generator.plugin.commonApi.MapperUtilCommon.checkNotEmpty; import static com.sngular.api.generator.plugin.commonApi.MapperUtilCommon.checkTextValueNotNull; import static com.sngular.api.generator.plugin.commonApi.MapperUtilCommon.getTextValue; import static com.sngular.api.generator.plugin.commonApi.MapperUtilCommon.isArraySchema; import static com.sngular.api.generator.plugin.commonApi.MapperUtilCommon.isMapSchema; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.ARRAY; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.BIG_DECIMAL; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.DOUBLE; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.FLOAT; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.INTEGER; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.LONG; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.MAP; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.OBJECT; -import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType.STRING; +import static com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType; import com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectProperties; @@ -50,6 +33,7 @@ import com.sngular.api.generator.plugin.openapi.model.SchemaFieldObject; import com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType; import com.sngular.api.generator.plugin.openapi.model.SchemaObject; +import com.sngular.api.generator.plugin.openapi.model.TypeConstants; import com.sngular.api.generator.plugin.openapi.parameter.SpecFile; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -291,7 +275,7 @@ private static List processFieldObjectList( .builder() .restrictionProperties(new SchemaFieldObjectProperties()) .baseName(fieldName) - .dataType(new SchemaFieldObjectType(OBJECT)) + .dataType(new SchemaFieldObjectType(TypeConstants.OBJECT)) .build()); } else if (MapperUtilCommon.isObjectSchema(schema) ) { if ((ObjectUtils.allNull(className, fieldName)) && (checkNotEmpty(schema,PROPERTIES))) { @@ -500,6 +484,26 @@ private static List processAdditionalProperties( return fieldObjectArrayList; } + private static void addPropertiesToFieldObject(final SchemaFieldObject fieldObject, final Schema value) { + fieldObject.getRestrictionProperties().setPattern(value.getPattern()); + fieldObject.getRestrictionProperties().setMaxItems(value.getMaxItems()); + fieldObject.getRestrictionProperties().setMinItems(value.getMinItems()); + fieldObject.getRestrictionProperties().setMaxLength(value.getMaxLength()); + fieldObject.getRestrictionProperties().setMinLength(value.getMinLength()); + fieldObject.getRestrictionProperties().setUniqueItems(value.getUniqueItems()); + fieldObject.getRestrictionProperties().setExclusiveMaximum(value.getExclusiveMaximum()); + fieldObject.getRestrictionProperties().setExclusiveMinimum(value.getExclusiveMinimum()); + if (Objects.nonNull(value.getMultipleOf())) { + fieldObject.getRestrictionProperties().setMultipleOf(value.getMultipleOf().toString()); + } + if (Objects.nonNull(value.getMaximum())) { + fieldObject.getRestrictionProperties().setMaximum(value.getMaximum().toString()); + } + if (Objects.nonNull(value.getMinimum())) { + fieldObject.getRestrictionProperties().setMinimum(value.getMinimum().toString()); + } + } + private static List processArray( final String fieldName, final String className, final JsonNode schema, final SpecFile specFile, final Map totalSchemas, final Map compositedSchemas, final List antiLoopList) { @@ -536,8 +540,7 @@ private static List processArray( fieldObjectArrayList.add(SchemaFieldObject .builder() .baseName(fieldName) - .restrictionProperties(new SchemaFieldObjectProperties()) - .dataType(SchemaFieldObjectType.fromTypeList(ARRAY, schemaObjectComposed.getClassName())) + .dataType(SchemaFieldObjectType.fromTypeList(TypeConstants.ARRAY, schemaObjectComposed.getClassName())) .importClass(schemaObjectComposed.getClassName()) .build()); } else if (checkNotEmpty(items,PROPERTIES)) { @@ -622,19 +625,86 @@ private static void getTypeImports(final HashMap> listHashM if (type.containsType(BIG_DECIMAL)) { listHashMap.computeIfAbsent(BIG_DECIMAL, key -> List.of("java.math.BigDecimal")); } + + if (type.containsType(TypeConstants.LOCALDATE)) { + listHashMap.computeIfAbsent(TypeConstants.LOCALDATE, key -> List.of("java.time.LocalDate")); + } + + if (type.containsType(TypeConstants.LOCALDATETIME)) { + listHashMap.computeIfAbsent(TypeConstants.LOCALDATETIME, key -> List.of("java.time.LocalDateTime")); + } + + if (type.containsType(TypeConstants.ZONEDDATE)) { + listHashMap.computeIfAbsent(TypeConstants.ZONEDDATETIME, key -> List.of("java.time.ZonedDateTime")); + } + + if (type.containsType(TypeConstants.ZONEDDATETIME)) { + listHashMap.computeIfAbsent(TypeConstants.ZONEDDATETIME, key -> List.of("java.time.ZonedDateTime")); + } + + if (type.containsType(TypeConstants.OFFSETDATE)) { + listHashMap.computeIfAbsent(TypeConstants.OFFSETDATETIME, key -> List.of("java.time.OffsetDateTime")); + } + + if (type.containsType(TypeConstants.OFFSETDATETIME)) { + listHashMap.computeIfAbsent(TypeConstants.OFFSETDATETIME, key -> List.of("java.time.OffsetDateTime")); + } } private static String getMapFieldType(final SchemaFieldObject schemaFieldObject) { final String fieldType = schemaFieldObject.getDataType().toString(); - String type; - if (fieldType.equals(STRING)) type = fieldType; - else type = OBJECT; + final String type; + switch (fieldType) { + case TypeConstants.BIG_DECIMAL: + case TypeConstants.INTEGER: + case TypeConstants.DOUBLE: + case TypeConstants.FLOAT: + case TypeConstants.LONG: + case TypeConstants.STRING: + type = fieldType; + break; + default: + type = TypeConstants.OBJECT; + break; + } return type; } private static String getImportClass(final String type) { - return StringUtils.isNotBlank(type) && !BASIC_TYPES.contains(type) ? type : ""; + return StringUtils.isNotBlank(type) && !TypeConstants.NO_IMPORT_TYPE.contains(type) ? StringUtils.capitalize(type) : ""; + } + + private static String getDateType(final SpecFile specFile) { + final String dateType; + switch (specFile.getUseTimeType()) { + case ZONED: + dateType = TypeConstants.ZONEDDATE; + break; + case OFFSET: + dateType = TypeConstants.OFFSETDATE; + break; + default: + dateType = TypeConstants.LOCALDATE; + } + + return dateType; + } + + private static String getDateTimeType(final SpecFile specFile) { + final String dateTimeType; + switch (specFile.getUseTimeType()) { + case ZONED: + dateTimeType = TypeConstants.ZONEDDATETIME; + break; + case OFFSET: + dateTimeType = TypeConstants.OFFSETDATETIME; + break; + default: + dateTimeType = TypeConstants.LOCALDATETIME; + } + + return dateTimeType; } private static void addPropertiesToFieldObject(final SchemaFieldObject fieldObject, final JsonNode value) { 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 23044b5d..166a6496 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 @@ -23,7 +23,6 @@ import com.sngular.api.generator.plugin.commonApi.MapperUtilCommon; import com.sngular.api.generator.plugin.openapi.exception.DuplicatedOperationException; import com.sngular.api.generator.plugin.openapi.model.AuthSchemaObject; -import com.sngular.api.generator.plugin.openapi.model.BasicTypeConstants; import com.sngular.api.generator.plugin.openapi.model.ContentObject; import com.sngular.api.generator.plugin.openapi.model.GlobalObject; import com.sngular.api.generator.plugin.openapi.model.OperationObject; @@ -31,6 +30,7 @@ import com.sngular.api.generator.plugin.openapi.model.PathObject; import com.sngular.api.generator.plugin.openapi.model.RequestObject; import com.sngular.api.generator.plugin.openapi.model.ResponseObject; +import com.sngular.api.generator.plugin.openapi.model.TypeConstants; import com.sngular.api.generator.plugin.openapi.parameter.SpecFile; import org.apache.commons.lang3.StringUtils; @@ -241,7 +241,7 @@ private static void fillParameterObjects( final String[] wholeRef = parameterNode.get(REF).textValue().split(SLASH); final String ref = wholeRef[wholeRef.length - 1]; JsonNode refParameter = null; - + if (checkNotEmpty(parameters, COMPONENTS) && checkNotEmpty(parameters.get(COMPONENTS), PARAMETERS)){ refParameter = parameters.get(COMPONENTS).get(PARAMETERS).get(ref); } @@ -413,7 +413,7 @@ private static String defineTypeName(final JsonNode schema, final GlobalObject g } return typeName; } - + private static String getListName(final GlobalObject globalObject, final String pojoName, final JsonNode arraySchema) { String typeName = null; if (arraySchema.get(ITEMS) != null && arraySchema.get(ITEMS).get(REF) != null) { diff --git a/multiapi-engine/src/main/resources/templates/openapi/templateSchema.ftlh b/multiapi-engine/src/main/resources/templates/openapi/templateSchema.ftlh index 8d2833d7..26cf6119 100644 --- a/multiapi-engine/src/main/resources/templates/openapi/templateSchema.ftlh +++ b/multiapi-engine/src/main/resources/templates/openapi/templateSchema.ftlh @@ -119,19 +119,19 @@ public class ${schema.className} { <#if field.required?has_content && field.required == true> @NotNull - <#if field.dataType.baseType == "Array"> + <#if field.dataType.baseType == "array"> <#if field.required> private final ${field.dataType} ${field.baseName?uncap_first}; <#else> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Map"> + <#elseif field.dataType.baseType == "map"> <#if field.required> private final ${field.dataType} ${field.baseName?uncap_first}; <#else> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Enum"> + <#elseif field.dataType.baseType == "enum"> <#if field.required> private final ${field.baseName?cap_first} ${field.baseName?uncap_first}; <#else> @@ -158,7 +158,7 @@ public class ${schema.className} { return String.valueOf(value); } } - <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object"> + <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object"> <#if field.required> private final ${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}; <#else> @@ -174,7 +174,7 @@ public class ${schema.className} { private ${schema.className}(<@compress single_line=true><#list schema.fieldObjectList as field> - <#if field.dataType.baseType == "Enum">${field.baseName?cap_first} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "Array">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "Map">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object">${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}<#else>${field.dataType?cap_first} ${field.baseName?uncap_first}<#sep>, ) { + <#if field.dataType.baseType == "enum">${field.baseName?cap_first} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "array">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "map">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object">${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}<#else>${field.dataType?cap_first} ${field.baseName?uncap_first}<#sep>, ) { <#list schema.fieldObjectList as field> this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; @@ -214,20 +214,20 @@ public class ${schema.className} { public static class ${schema.className}Builder { <#list schema.fieldObjectList as field> - <#if field.dataType.baseType == "Array"> + <#if field.dataType.baseType == "array"> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Map"> + <#elseif field.dataType.baseType == "map"> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Enum"> + <#elseif field.dataType.baseType == "enum"> private ${field.baseName?cap_first} ${field.baseName?uncap_first}; - <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object"> + <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object"> private ${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}; <#else> private ${field.dataType?cap_first} ${field.baseName?uncap_first}; <#list schema.fieldObjectList as field> - <#if field.dataType.baseType == "Array"> + <#if field.dataType.baseType == "array"> public ${schema.className}.${schema.className}Builder ${field.baseName?uncap_first}(${field.dataType} ${field.baseName?uncap_first}) { if (!${field.baseName?uncap_first}.isEmpty()) { this.${field.baseName?uncap_first}.addAll(${field.baseName?uncap_first}); @@ -241,7 +241,7 @@ public class ${schema.className} { } return this; } - <#elseif field.dataType.baseType == "Map"> + <#elseif field.dataType.baseType == "map"> public ${schema.className}.${schema.className}Builder ${field.baseName?uncap_first}(${field.dataType} ${field.baseName?uncap_first}) { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; return this; @@ -251,12 +251,12 @@ public class ${schema.className} { this.${field.baseName?uncap_first}.put(key, value); return this; } - <#elseif field.dataType.baseType == "Enum"> + <#elseif field.dataType.baseType == "enum"> public ${schema.className}.${schema.className}Builder ${field.baseName?uncap_first}(${field.baseName?cap_first} ${field.baseName}) { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; return this; } - <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object"> + <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object"> public ${schema.className}.${schema.className}Builder ${field.baseName?uncap_first}(${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}) { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; return this; @@ -282,7 +282,7 @@ public class ${schema.className} { * @return ${field.baseName?uncap_first} */ @Schema(name = "${field.baseName?uncap_first}", required = <#if field.required?has_content && field.required == true>true<#else>false) - <#if field.dataType.baseType == "Array"> + <#if field.dataType.baseType == "array"> public ${field.dataType} get${field.baseName?cap_first}() { return ${field.baseName?uncap_first}; } @@ -291,7 +291,7 @@ public class ${schema.className} { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; } - <#elseif field.dataType.baseType == "Map"> + <#elseif field.dataType.baseType == "map"> public ${field.dataType} get${field.baseName?cap_first}() { return ${field.baseName?uncap_first}; } @@ -300,7 +300,7 @@ public class ${schema.className} { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; } - <#elseif field.dataType.baseType == "Enum"> + <#elseif field.dataType.baseType == "enum"> public ${field.baseName?cap_first} get${field.baseName?cap_first}() { return ${field.baseName?uncap_first}; } @@ -309,7 +309,7 @@ public class ${schema.className} { this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; } - <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object"> + <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object"> public ${field.dataType.innerType?cap_first} get${field.baseName?cap_first}() { return ${field.baseName?uncap_first}; } diff --git a/multiapi-engine/src/main/resources/templates/openapi/templateSchemaWithLombok.ftlh b/multiapi-engine/src/main/resources/templates/openapi/templateSchemaWithLombok.ftlh index 00904a55..735e3c13 100644 --- a/multiapi-engine/src/main/resources/templates/openapi/templateSchemaWithLombok.ftlh +++ b/multiapi-engine/src/main/resources/templates/openapi/templateSchemaWithLombok.ftlh @@ -5,7 +5,7 @@ import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; <#list schema.fieldObjectList as field> - <#if field.dataType.baseType == "Enum"> + <#if field.dataType.baseType == "enum"> import com.fasterxml.jackson.annotation.JsonValue; <#break> @@ -115,11 +115,11 @@ public class ${schema.className} { <#if field.required?has_content && field.required == true> @NonNull - <#if field.dataType.baseType == "Array"> + <#if field.dataType.baseType == "array"> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Map"> + <#elseif field.dataType.baseType == "map"> private ${field.dataType} ${field.baseName?uncap_first} = new ${field.dataType?api.getImplementationTypeString()}(); - <#elseif field.dataType.baseType == "Enum"> + <#elseif field.dataType.baseType == "enum"> private ${field.baseName?cap_first} ${field.baseName?uncap_first}; public enum ${field.baseName?cap_first} { @@ -143,7 +143,7 @@ public class ${schema.className} { return String.valueOf(value); } } - <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object"> + <#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object"> private ${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}; <#else> private ${field.dataType?cap_first} ${field.baseName?uncap_first}; @@ -154,7 +154,7 @@ public class ${schema.className} { @Builder @Jacksonized private ${schema.className}(<@compress single_line=true><#list schema.fieldObjectList as field> - <#if field.required>@NonNull <#if field.dataType.baseType == "Enum">${field.baseName?cap_first} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "Array">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "Map">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.innerType?has_content && field.dataType.baseType == "Object">${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}<#else>${field.dataType?cap_first} ${field.baseName?uncap_first}<#sep>, ) { + <#if field.required>@NonNull <#if field.dataType.baseType == "enum">${field.baseName?cap_first} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "array">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.baseType == "map">${field.dataType} ${field.baseName?uncap_first}<#elseif field.dataType.innerType?has_content && field.dataType.baseType == "object">${field.dataType.innerType?cap_first} ${field.baseName?uncap_first}<#else>${field.dataType?cap_first} ${field.baseName?uncap_first}<#sep>, ) { <#list schema.fieldObjectList as field> this.${field.baseName?uncap_first} = ${field.baseName?uncap_first}; 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 fb1c1222..0f466330 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 @@ -15,6 +15,7 @@ import java.util.List; import java.util.function.Function; +import com.sngular.api.generator.plugin.openapi.model.TypeConstants.TimeType; import com.sngular.api.generator.plugin.openapi.parameter.SpecFile; import com.sngular.api.generator.test.utils.TestUtils; import org.apache.commons.collections4.CollectionUtils; @@ -351,6 +352,44 @@ public final class OpenApiGeneratorFixtures { .build() ); + static final List TEST_DATE_TIME = List.of( + SpecFile + .builder() + .filePath("openapigenerator/testDateTime/api-test.yml") + .apiPackage("com.sngular.multifileplugin.testDateTime") + .modelPackage("com.sngular.multifileplugin.testDateTime.model") + .clientPackage("com.sngular.multifileplugin.testDateTime.client") + .modelNameSuffix("DTO") + .useLombokModelAnnotation(true) + .build() + ); + + static final List TEST_DATE_TIME_ZONED = List.of( + SpecFile + .builder() + .filePath("openapigenerator/testDateTimeZoned/api-test.yml") + .apiPackage("com.sngular.multifileplugin.testDateTimeZoned") + .modelPackage("com.sngular.multifileplugin.testDateTimeZoned.model") + .clientPackage("com.sngular.multifileplugin.testDateTimeZoned.client") + .modelNameSuffix("DTO") + .useLombokModelAnnotation(true) + .useTimeType(TimeType.ZONED) + .build() + ); + + static final List TEST_DATE_TIME_OFFSET = List.of( + SpecFile + .builder() + .filePath("openapigenerator/testDateTimeOffset/api-test.yml") + .apiPackage("com.sngular.multifileplugin.testDateTimeOffset") + .modelPackage("com.sngular.multifileplugin.testDateTimeOffset.model") + .clientPackage("com.sngular.multifileplugin.testDateTimeOffset.client") + .modelNameSuffix("DTO") + .useLombokModelAnnotation(true) + .useTimeType(TimeType.OFFSET) + .build() + ); + static Function validateOneOfInResponse() { final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testoneofinresponse"; @@ -1082,6 +1121,60 @@ static Function validateCreateDTO() { return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, Collections.emptyList(), DEFAULT_EXCEPTION_API); } + static Function validateDateTime() { + final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testDateTime"; + + final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testDateTime/model"; + + final String DEFAULT_EXCEPTION_API = "generated/com/sngular/multifileplugin/testDateTime/model/exception"; + + final List expectedTestApiFile = List.of( + "openapigenerator/testDateTime/assets/TestApi.java" + ); + + final List expectedTestApiModelFiles = List.of( + "openapigenerator/testDateTime/assets/model/TestDateDTO.java" + ); + + return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, Collections.emptyList(), DEFAULT_EXCEPTION_API); + } + + static Function validateDateTimeZoned() { + final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testDateTimeZoned"; + + final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testDateTimeZoned/model"; + + final String DEFAULT_EXCEPTION_API = "generated/com/sngular/multifileplugin/testDateTimeZoned/model/exception"; + + final List expectedTestApiFile = List.of( + "openapigenerator/testDateTimeZoned/assets/TestApi.java" + ); + + final List expectedTestApiModelFiles = List.of( + "openapigenerator/testDateTimeZoned/assets/model/TestDateDTO.java" + ); + + return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, Collections.emptyList(), DEFAULT_EXCEPTION_API); + } + + static Function validateDateTimeOffset() { + final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testDateTimeOffset"; + + final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testDateTimeOffset/model"; + + final String DEFAULT_EXCEPTION_API = "generated/com/sngular/multifileplugin/testDateTimeOffset/model/exception"; + + final List expectedTestApiFile = List.of( + "openapigenerator/testDateTimeOffset/assets/TestApi.java" + ); + + final List expectedTestApiModelFiles = List.of( + "openapigenerator/testDateTimeOffset/assets/model/TestDateDTO.java" + ); + + return (path) -> commonTest(path, expectedTestApiFile, expectedTestApiModelFiles, DEFAULT_TARGET_API, DEFAULT_MODEL_API, Collections.emptyList(), DEFAULT_EXCEPTION_API); + } + 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 d352df2f..be24632f 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 @@ -83,7 +83,13 @@ static Stream fileSpecToProcess() { Arguments.of("testValidationAnnotationsLombok", OpenApiGeneratorFixtures.TEST_VALIDATION_ANNOTATIONS_LOMBOK, OpenApiGeneratorFixtures.validateValidationAnnotationsLombok()), Arguments.of("testCreateDTO", OpenApiGeneratorFixtures.TEST_CREATE_DTO, - OpenApiGeneratorFixtures.validateCreateDTO()) + OpenApiGeneratorFixtures.validateCreateDTO()), + Arguments.of("testDateTime", OpenApiGeneratorFixtures.TEST_DATE_TIME, + OpenApiGeneratorFixtures.validateDateTime()), + Arguments.of("testDateTimeZoned", OpenApiGeneratorFixtures.TEST_DATE_TIME_ZONED, + OpenApiGeneratorFixtures.validateDateTimeZoned()), + Arguments.of("testDateTimeOffset", OpenApiGeneratorFixtures.TEST_DATE_TIME_OFFSET, + OpenApiGeneratorFixtures.validateDateTimeOffset()) ); } diff --git a/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSchemaDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSchemaDTO.java index 21e42de0..39c3c999 100644 --- a/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSchemaDTO.java +++ b/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSchemaDTO.java @@ -6,9 +6,9 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; +import com.sngular.multifileplugin.testcomplexanyof.model.ApiTypeArrayDTO; import java.util.List; import java.util.ArrayList; -import com.sngular.multifileplugin.testcomplexanyof.model.ApiTypeArrayDTO; import com.sngular.multifileplugin.testcomplexanyof.model.exception.ModelClassException; import com.sngular.multifileplugin.testcomplexanyof.model.customvalidator.NotNull; diff --git a/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSequenceFieldDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSequenceFieldDTO.java index 4efbbfe6..dc2b0189 100644 --- a/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSequenceFieldDTO.java +++ b/multiapi-engine/src/test/resources/openapigenerator/testComplexAnyOf/assets/ApiSequenceFieldDTO.java @@ -7,9 +7,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import io.swagger.v3.oas.annotations.media.Schema; +import com.sngular.multifileplugin.testcomplexanyof.model.ApiTypeArrayDTO; import java.util.List; import java.util.ArrayList; -import com.sngular.multifileplugin.testcomplexanyof.model.ApiTypeArrayDTO; @JsonDeserialize(builder = ApiSequenceFieldDTO.ApiSequenceFieldDTOBuilder.class) public class ApiSequenceFieldDTO { diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTime/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/api-test.yml new file mode 100644 index 00000000..3d9e1813 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/api-test.yml @@ -0,0 +1,30 @@ +openapi: 3.0.2 +info: + title: Testing example file + version: 1.0.0 +servers: +- url: http://localhost/v1 +paths: + /test: + get: + tags: + - test + operationId: testDateTime + responses: + '200': + description: An object with date and date-time formats + content: + application/json: + schema: + $ref: '#/components/schemas/testDate' +components: + schemas: + testDate: + type: object + properties: + someDate: + type: string + format: date + someTime: + type: string + format: date-time diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/TestApi.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/TestApi.java new file mode 100644 index 00000000..53f6f3e2 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/TestApi.java @@ -0,0 +1,45 @@ +package com.sngular.multifileplugin.testDateTime; + +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.testDateTime.model.TestDateDTO; + +public interface TestApi { + + /** + * GET /test + * @return An object with date and date-time formats; (status code 200) + */ + + @Operation( + operationId = "testDateTime", + tags = {"test"}, + responses = { + @ApiResponse(responseCode = "200", description = "An object with date and date-time formats", content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestDateDTO.class))) + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = "/test", + produces = {"application/json"} + ) + + default ResponseEntity testDateTime() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/model/TestDateDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/model/TestDateDTO.java new file mode 100644 index 00000000..ac5b945c --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTime/assets/model/TestDateDTO.java @@ -0,0 +1,30 @@ +package com.sngular.multifileplugin.testDateTime.model; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDate; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; + +@Data +public class TestDateDTO { + + @JsonProperty(value ="someDate") + private LocalDate someDate; + + @JsonProperty(value ="someTime") + private LocalDateTime someTime; + + + @Builder + @Jacksonized + private TestDateDTO(LocalDate someDate, LocalDateTime someTime) { + this.someDate = someDate; + this.someTime = someTime; + + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/api-test.yml new file mode 100644 index 00000000..3d9e1813 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/api-test.yml @@ -0,0 +1,30 @@ +openapi: 3.0.2 +info: + title: Testing example file + version: 1.0.0 +servers: +- url: http://localhost/v1 +paths: + /test: + get: + tags: + - test + operationId: testDateTime + responses: + '200': + description: An object with date and date-time formats + content: + application/json: + schema: + $ref: '#/components/schemas/testDate' +components: + schemas: + testDate: + type: object + properties: + someDate: + type: string + format: date + someTime: + type: string + format: date-time diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/TestApi.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/TestApi.java new file mode 100644 index 00000000..53a6d10a --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/TestApi.java @@ -0,0 +1,45 @@ +package com.sngular.multifileplugin.testDateTimeOffset; + +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.testDateTimeOffset.model.TestDateDTO; + +public interface TestApi { + + /** + * GET /test + * @return An object with date and date-time formats; (status code 200) + */ + + @Operation( + operationId = "testDateTime", + tags = {"test"}, + responses = { + @ApiResponse(responseCode = "200", description = "An object with date and date-time formats", content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestDateDTO.class))) + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = "/test", + produces = {"application/json"} + ) + + default ResponseEntity testDateTime() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/model/TestDateDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/model/TestDateDTO.java new file mode 100644 index 00000000..3a6fc079 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeOffset/assets/model/TestDateDTO.java @@ -0,0 +1,29 @@ +package com.sngular.multifileplugin.testDateTimeOffset.model; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import lombok.Builder; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; + +@Data +public class TestDateDTO { + + @JsonProperty(value ="someDate") + private OffsetDateTime someDate; + + @JsonProperty(value ="someTime") + private OffsetDateTime someTime; + + + @Builder + @Jacksonized + private TestDateDTO(OffsetDateTime someDate, OffsetDateTime someTime) { + this.someDate = someDate; + this.someTime = someTime; + + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/api-test.yml new file mode 100644 index 00000000..3d9e1813 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/api-test.yml @@ -0,0 +1,30 @@ +openapi: 3.0.2 +info: + title: Testing example file + version: 1.0.0 +servers: +- url: http://localhost/v1 +paths: + /test: + get: + tags: + - test + operationId: testDateTime + responses: + '200': + description: An object with date and date-time formats + content: + application/json: + schema: + $ref: '#/components/schemas/testDate' +components: + schemas: + testDate: + type: object + properties: + someDate: + type: string + format: date + someTime: + type: string + format: date-time diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/TestApi.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/TestApi.java new file mode 100644 index 00000000..a5b31dee --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/TestApi.java @@ -0,0 +1,45 @@ +package com.sngular.multifileplugin.testDateTimeZoned; + +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.testDateTimeZoned.model.TestDateDTO; + +public interface TestApi { + + /** + * GET /test + * @return An object with date and date-time formats; (status code 200) + */ + + @Operation( + operationId = "testDateTime", + tags = {"test"}, + responses = { + @ApiResponse(responseCode = "200", description = "An object with date and date-time formats", content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestDateDTO.class))) + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = "/test", + produces = {"application/json"} + ) + + default ResponseEntity testDateTime() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/model/TestDateDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/model/TestDateDTO.java new file mode 100644 index 00000000..24a25b9e --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testDateTimeZoned/assets/model/TestDateDTO.java @@ -0,0 +1,29 @@ +package com.sngular.multifileplugin.testDateTimeZoned.model; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.ZonedDateTime; +import lombok.Builder; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; + +@Data +public class TestDateDTO { + + @JsonProperty(value ="someDate") + private ZonedDateTime someDate; + + @JsonProperty(value ="someTime") + private ZonedDateTime someTime; + + + @Builder + @Jacksonized + private TestDateDTO(ZonedDateTime someDate, ZonedDateTime someTime) { + this.someDate = someDate; + this.someTime = someTime; + + } + +} diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle index 35fffb20..f5175620 100644 --- a/scs-multiapi-gradle-plugin/build.gradle +++ b/scs-multiapi-gradle-plugin/build.gradle @@ -20,7 +20,7 @@ repositories { } group = 'com.sngular' -version = '4.5.2' +version = '4.6.1' def SCSMultiApiPluginGroupId = group def SCSMultiApiPluginVersion = version @@ -30,7 +30,7 @@ dependencies { shadow localGroovy() shadow gradleApi() - implementation 'com.sngular:multiapi-engine:4.5.2' + implementation 'com.sngular:multiapi-engine:4.6.1' testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'com.puppycrawl.tools:checkstyle:10.3.1' } @@ -98,7 +98,7 @@ testing { integrationTest(JvmTestSuite) { dependencies { - implementation 'com.sngular:scs-multiapi-gradle-plugin:4.5.2' + implementation 'com.sngular:scs-multiapi-gradle-plugin:4.6.1' implementation 'org.assertj:assertj-core:3.23.1' } diff --git a/scs-multiapi-maven-plugin/pom.xml b/scs-multiapi-maven-plugin/pom.xml index d0e52d85..deb2c7fc 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 - 4.5.2 + 4.6.1 maven-plugin AsyncApi - OpenApi Code Generator Maven Plugin @@ -144,9 +144,9 @@ Europe/Madrid - davidgayoso - David Gayoso Salvado - david.gayoso@sngular.com + 5uso-sng + Jesús Mosteiro García + jesus.mosteiro@sngular.com Sngular https://www.sngular.com @@ -155,9 +155,9 @@ Europe/Madrid - janDuinRod - Jan Duinkerken Rodríguez - jan.duinkerken@sngular.com + davidgayoso + David Gayoso Salvado + david.gayoso@sngular.com Sngular https://www.sngular.com @@ -166,9 +166,9 @@ Europe/Madrid - 5uso-sng - Jesús Mosteiro García - jesus.mosteiro@sngular.com + janDuinRod + Jan Duinkerken Rodríguez + jan.duinkerken@sngular.com Sngular https://www.sngular.com @@ -223,7 +223,7 @@ com.sngular multiapi-engine - 4.5.2 + 4.6.1 org.apache.maven @@ -392,6 +392,7 @@ + org.apache.maven.plugins maven-assembly-plugin 3.4.2