From 95bc64bc60307357915599e72b495ea8a138ef7b Mon Sep 17 00:00:00 2001 From: altro3 Date: Wed, 20 Nov 2024 22:39:30 +0700 Subject: [PATCH] Fix discriminator override for kotlin Fixed #1881 --- .../AbstractMicronautKotlinCodegen.java | 3 +- .../io/micronaut/openapi/generator/Utils.java | 11 ++- .../openapitools/codegen/DefaultCodegen.java | 4 +- .../kotlin-micronaut/client/api.mustache | 2 +- .../client/auth/Authorization.mustache | 2 +- .../client/auth/AuthorizationBinder.mustache | 15 ++-- .../client/auth/AuthorizationFilter.mustache | 12 +-- .../client/auth/Authorizations.mustache | 2 +- .../ApiKeyAuthConfiguration.mustache | 29 +++---- .../HttpBasicAuthConfiguration.mustache | 9 +- .../client/params/bodyParams.mustache | 2 +- .../client/params/formParams.mustache | 2 +- .../common/model/oneof_interface.mustache | 2 +- .../common/model/typeInfoAnnotation.mustache | 4 +- .../common/operationAnnotations.mustache | 14 ++-- .../server/controller-interface.mustache | 2 +- .../KotlinMicronautClientCodegenTest.java | 82 +++++++++++++++---- .../KotlinMicronautServerCodegenTest.java | 30 +++---- 18 files changed, 139 insertions(+), 88 deletions(-) diff --git a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java index 604328bde9..cdd1f0408e 100644 --- a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java +++ b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java @@ -29,6 +29,7 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.servers.Server; import org.apache.commons.lang3.StringUtils; @@ -2102,7 +2103,7 @@ private void processVar(CodegenModel model, List vars, List"; typeWithEnumWithGenericAnnotations = "Map"; } else if (containerType != null) { - var genericAnnotations = genericAnnotations(itemsProp, isGenerateHardNullable); + genericAnnotations = genericAnnotations(itemsProp, isGenerateHardNullable); processGenericAnnotations(itemsProp, useBeanValidation, isGenerateHardNullable, itemsProp.isNullable, itemsProp.required, itemsProp.isReadOnly, withNullablePostfix); typeWithGenericAnnotations = containerType + "<" + genericAnnotations + itemsProp.vendorExtensions.get("typeWithGenericAnnotations") + ">"; typeWithEnumWithGenericAnnotations = containerType + "<" + genericAnnotations + itemsProp.vendorExtensions.get("typeWithEnumWithGenericAnnotations") + ">"; } } - ext.put("typeWithGenericAnnotations", typeWithGenericAnnotations + (withNullablePostfix && (isNullable || isRequired && isReadonly) ? "?" : "")); - ext.put("typeWithEnumWithGenericAnnotations", typeWithEnumWithGenericAnnotations + (withNullablePostfix && (isNullable || isRequired && isReadonly) ? "?" : "")); + var isNullableType = withNullablePostfix && (isNullable || isRequired && isReadonly || (genericAnnotations != null && !genericAnnotations.contains("NotNull") && !isRequired)); + + ext.put("typeWithGenericAnnotations", typeWithGenericAnnotations + (isNullableType ? "?" : "")); + ext.put("typeWithEnumWithGenericAnnotations", typeWithEnumWithGenericAnnotations + (isNullableType ? "?" : "")); } private static String genericAnnotations(CodegenProperty prop, boolean isGenerateHardNullable) { diff --git a/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 13314bfe90..ff2825b5b4 100644 --- a/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -4293,7 +4293,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo property.defaultValueWithParam = toDefaultValueWithParam(name, p); LOGGER.debug("debugging from property return: {}", property); - schemaCodegenPropertyCache.put(ns, property); +// schemaCodegenPropertyCache.put(ns, property); return property; } @@ -6072,7 +6072,7 @@ protected void addVars(IJsonSchemaValidationProperties m, List } else { final CodegenProperty cp; - if (cm != null && cm.allVars == vars && varsMap.keySet().contains(key)) { + if (cm != null && cm.allVars == vars && varsMap.containsKey(key)) { // when updating allVars, reuse the codegen property from the child model if it's already present // the goal is to avoid issues when the property is defined in both child, parent but the // definition is not identical, e.g. required vs optional, integer vs string diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/api.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/api.mustache index 31c7facca9..62d3e9fbd7 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/api.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/api.mustache @@ -66,7 +66,7 @@ interface {{classname}} { {{{.}}} {{/vendorExtensions.x-operation-extra-annotation}} fun {{nickname}}({{#allParams}} - {{#formatSingleLine}}{{>client/params/queryParams}}{{>client/params/pathParams}}{{>client/params/headerParams}}{{>client/params/bodyParams}}{{>client/params/formParams}}{{>client/params/cookieParams}}{{^-last}},{{/-last}}{{/formatSingleLine}} + {{#formatSingleLine}}{{>client/params/queryParams}}{{>client/params/pathParams}}{{>client/params/headerParams}}{{>client/params/bodyParams}}{{>client/params/formParams}}{{>client/params/cookieParams}},{{/formatSingleLine}} {{/allParams}}){{#returnType}}: {{{returnType}}}{{/returnType}} {{/formatNoEmptyLines}} {{/operation}} diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorization.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorization.mustache index 64f9b1766f..935c027726 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorization.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorization.mustache @@ -27,5 +27,5 @@ annotation class Authorization( /** * The scopes for the oauth authorization. */ - val scopes: Array = [] + val scopes: Array = [], ) diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationBinder.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationBinder.mustache index 70ffa0abdb..2b833a4b53 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationBinder.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationBinder.mustache @@ -24,19 +24,20 @@ open class AuthorizationBinder : AnnotatedClientRequestBinder { return Authorization::class.java } - override fun bind(@NonNull context: MethodInvocationContext, - @NonNull uriContext: ClientRequestUriContext, - @NonNull request: MutableHttpRequest<*> + override fun bind( + @NonNull context: MethodInvocationContext, + @NonNull uriContext: ClientRequestUriContext, + @NonNull request: MutableHttpRequest<*>, ) { val annotations: List> = context.annotationMetadata - .getAnnotationValuesByType(Authorization::class.java) + .getAnnotationValuesByType(Authorization::class.java) if (annotations.isNotEmpty()) { val authorizationNames = ArrayList() for (ann in annotations) { ann.stringValue("value") - .filter{ s -> !s.isNullOrEmpty() } - .ifPresent { v -> authorizationNames.add(configurationName(v)) } + .filter{ s -> !s.isNullOrEmpty() } + .ifPresent { v -> authorizationNames.add(configurationName(v)) } } request.setAttribute(AUTHORIZATION_NAMES, authorizationNames) } @@ -47,6 +48,6 @@ open class AuthorizationBinder : AnnotatedClientRequestBinder { } companion object { - var AUTHORIZATION_NAMES = "micronaut.security.AUTHORIZATION_NAMES" + const val AUTHORIZATION_NAMES = "micronaut.security.AUTHORIZATION_NAMES" } } diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationFilter.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationFilter.mustache index 97dea3c39e..bd989d1e65 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationFilter.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/AuthorizationFilter.mustache @@ -45,15 +45,15 @@ open class AuthorizationFilter( init { clientConfigurationByName = clientConfigurations - .filter { it.isEnabled } - .collect(Collectors.toMap({ it.name }, { it })) - tokenPropagatorByName = HashMap() - clientCredentialsClientByName = HashMap() + .filter { it.isEnabled } + .collect(Collectors.toMap({ it.name }, { it })) + tokenPropagatorByName = mutableMapOf() + clientCredentialsClientByName = mutableMapOf() authorizationsByName = configurableAuthorizations - .collect(Collectors.toMap({ it.name }, { it })) + .collect(Collectors.toMap({ it.name }, { it })) } - override fun doFilter(request: @NonNull MutableHttpRequest<*>, chain: @NonNull ClientFilterChain): Publisher?> { + override fun doFilter(@NonNull request: MutableHttpRequest<*>, @NonNull chain: ClientFilterChain): Publisher?> { val names = request.getAttribute(AuthorizationBinder.AUTHORIZATION_NAMES, MutableList::class.java).orElse(null) if (names.isNullOrEmpty()) { return chain.proceed(request) diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorizations.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorizations.mustache index e437d71dea..d7b2b6d187 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorizations.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/Authorizations.mustache @@ -19,5 +19,5 @@ import {{javaxPackage}}.annotation.Generated @Bindable annotation class Authorizations( - val value: Array + val value: Array, ) diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/ApiKeyAuthConfiguration.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/ApiKeyAuthConfiguration.mustache index 0c0689dd64..93a26a7a87 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/ApiKeyAuthConfiguration.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/ApiKeyAuthConfiguration.mustache @@ -15,31 +15,28 @@ import {{javaxPackage}}.annotation.Generated {{>common/generatedAnnotation}} {{/generatedAnnotation}} @EachProperty("security.api-key-auth") -data class ApiKeyAuthConfiguration @ConfigurationInject -constructor( - @Parameter override val name: String, - @NonNull var location: AuthKeyLocation, - @NonNull var paramName: String, - @NonNull var apiKey: String +data class ApiKeyAuthConfiguration @ConfigurationInject constructor( + @Parameter + override val name: String, + @NonNull + var location: AuthKeyLocation, + @NonNull + var paramName: String, + @NonNull + var apiKey: String, ) : ConfigurableAuthorization { override fun applyAuthorization(@NonNull request: MutableHttpRequest<*>) { when (location) { - AuthKeyLocation.HEADER -> { - request.header(paramName, apiKey) - } - AuthKeyLocation.QUERY -> { - request.parameters.add(paramName, apiKey) - } - AuthKeyLocation.COOKIE -> { - request.cookie(Cookie.of(paramName, apiKey)) - } + AuthKeyLocation.HEADER -> request.header(paramName, apiKey) + AuthKeyLocation.QUERY -> request.parameters.add(paramName, apiKey) + AuthKeyLocation.COOKIE -> request.cookie(Cookie.of(paramName, apiKey)) } } enum class AuthKeyLocation { HEADER, QUERY, - COOKIE + COOKIE, } } diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/HttpBasicAuthConfiguration.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/HttpBasicAuthConfiguration.mustache index 0ec240d6c2..18329664a9 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/HttpBasicAuthConfiguration.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/auth/configuration/HttpBasicAuthConfiguration.mustache @@ -15,9 +15,12 @@ import {{javaxPackage}}.annotation.Generated {{/generatedAnnotation}} @EachProperty("security.basic-auth") data class HttpBasicAuthConfiguration( - @Parameter override val name: String, - @NonNull var username: String, - @NonNull var password: String + @Parameter + override val name: String, + @NonNull + var username: String, + @NonNull + var password: String, ) : ConfigurableAuthorization { override fun applyAuthorization(@NonNull request: MutableHttpRequest<*>) { diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/bodyParams.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/bodyParams.mustache index 13bc87d40d..ad2f98a77d 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/bodyParams.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/bodyParams.mustache @@ -1 +1 @@ -{{#isBodyParam}}@Body {{>common/params/validation}}{{>client/params/type}}{{{paramName}}}: {{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{/isBodyParam}} \ No newline at end of file +{{#isBodyParam}}@Body {{>common/params/validation}}{{>client/params/type}}{{{paramName}}}: {{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{#vendorExtensions.defaultValueInit}} = {{{.}}}{{/vendorExtensions.defaultValueInit}}{{^vendorExtensions.defaultValueInit}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}}{{^required}} = null{{/required}}{{/isNullable}}{{/vendorExtensions.defaultValueInit}}{{/isBodyParam}} \ No newline at end of file diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/formParams.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/formParams.mustache index 23289e839b..72a300aaf1 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/formParams.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/client/params/formParams.mustache @@ -1 +1 @@ -{{#isFormParam}}{{>common/params/validation}}{{>client/params/type}}{{{paramName}}}: {{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{/isFormParam}} \ No newline at end of file +{{#isFormParam}}{{>common/params/validation}}{{>client/params/type}}{{{paramName}}}: {{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{#vendorExtensions.defaultValueInit}} = {{{.}}}{{/vendorExtensions.defaultValueInit}}{{^vendorExtensions.defaultValueInit}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}}{{^required}} = null{{/required}}{{/isNullable}}{{/vendorExtensions.defaultValueInit}}{{/isFormParam}} \ No newline at end of file diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/oneof_interface.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/oneof_interface.mustache index 89fa1d42f4..a83701c3da 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/oneof_interface.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/oneof_interface.mustache @@ -6,7 +6,7 @@ {{>common/generatedAnnotation}} {{/generatedAnnotation}} {{>common/model/typeInfoAnnotation}} -interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} : {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}}{{/formatNoEmptyLines}}{{#discriminator}} { +{{/formatNoEmptyLines}}interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} : {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}}{{#discriminator}} { val {{propertyName}}: {{propertyType}} } diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/typeInfoAnnotation.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/typeInfoAnnotation.mustache index 28c0d42172..609b49fdb0 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/typeInfoAnnotation.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/model/typeInfoAnnotation.mustache @@ -3,7 +3,7 @@ {{#jackson}} @JsonIgnoreProperties( value = ["{{{discriminator.propertyBaseName}}}"], // ignore manually set {{{discriminator.propertyBaseName}}}, it will be automatically generated by Jackson during serialization - allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization + allowSetters = true, // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization ) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "{{{discriminator.propertyBaseName}}}", visible = true) {{#vendorExtensions.hasMappedModels}} @@ -13,4 +13,4 @@ {{/vendorExtensions.hasMappedModels}} {{/jackson}} {{/discriminator.propertyBaseName}} -{{/discriminator}} +{{/discriminator}} \ No newline at end of file diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/operationAnnotations.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/operationAnnotations.mustache index 33bcd0de96..0ff4796820 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/operationAnnotations.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/common/operationAnnotations.mustache @@ -53,20 +53,20 @@ {{#responses}} ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = [ {{#produces}} - Content(mediaType = "{{{mediaType}}}", {{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class){{#isArray}}){{/isArray}}){{^-last}},{{/-last}} + Content(mediaType = "{{{mediaType}}}", {{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class){{#isArray}}){{/isArray}}), {{/produces}} - ]{{/baseType}}){{^-last}},{{/-last}} + ]{{/baseType}}), {{/responses}} - ]{{#vendorExtensions.hasNotBodyParam}}, + ],{{#vendorExtensions.hasNotBodyParam}} parameters = [ {{#vendorExtensions.swaggerParams}} - Parameter(name = "{{baseName}}"{{#isDeprecated}}, deprecated = true{{/isDeprecated}}{{#description}}, description = "{{{description}}}"{{/description}}{{#required}}, required = true{{/required}}, `in` = ParameterIn.{{#isCookieParam}}COOKIE{{/isCookieParam}}{{#isHeaderParam}}HEADER{{/isHeaderParam}}{{#isQueryParam}}QUERY{{/isQueryParam}}{{#isPathParam}}PATH{{/isPathParam}}){{^-last}},{{/-last}} + Parameter(name = "{{baseName}}"{{#isDeprecated}}, deprecated = true{{/isDeprecated}}{{#description}}, description = "{{{description}}}"{{/description}}{{#required}}, required = true{{/required}}, `in` = ParameterIn.{{#isCookieParam}}COOKIE{{/isCookieParam}}{{#isHeaderParam}}HEADER{{/isHeaderParam}}{{#isQueryParam}}QUERY{{/isQueryParam}}{{#isPathParam}}PATH{{/isPathParam}}), {{/vendorExtensions.swaggerParams}} - ]{{/vendorExtensions.hasNotBodyParam}}{{#hasAuthMethods}}, + ],{{/vendorExtensions.hasNotBodyParam}}{{#hasAuthMethods}} security = [ {{#authMethods}} - SecurityRequirement(name = "{{name}}"{{#isOAuth}}{{#scopes.1}}, scopes = [{{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}}]{{/scopes.1}}{{/isOAuth}}){{^-last}},{{/-last}} + SecurityRequirement(name = "{{name}}"{{#isOAuth}}{{#scopes.1}}, scopes = [{{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}}]{{/scopes.1}}{{/isOAuth}}), {{/authMethods}} - ]{{/hasAuthMethods}} + ],{{/hasAuthMethods}} ) {{/generateSwagger2Annotations}} diff --git a/openapi-generator/src/main/resources/templates/kotlin-micronaut/server/controller-interface.mustache b/openapi-generator/src/main/resources/templates/kotlin-micronaut/server/controller-interface.mustache index be60ee8fb0..1c0cbb6f7a 100644 --- a/openapi-generator/src/main/resources/templates/kotlin-micronaut/server/controller-interface.mustache +++ b/openapi-generator/src/main/resources/templates/kotlin-micronaut/server/controller-interface.mustache @@ -78,7 +78,7 @@ interface {{classname}} { {{#isDeprecated}} @java.lang.Deprecated {{/isDeprecated}} - {{{paramName}}}: {{#isEnum}}{{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{/isEnum}}{{^isEnum}}{{{vendorExtensions.typeWithGenericAnnotations}}}{{/isEnum}}{{^-last}},{{/-last}}{{/formatSingleLine}} + {{{paramName}}}: {{#isEnum}}{{{vendorExtensions.typeWithEnumWithGenericAnnotations}}}{{/isEnum}}{{^isEnum}}{{{vendorExtensions.typeWithGenericAnnotations}}}{{/isEnum}},{{/formatSingleLine}} {{/allParams}}){{#returnType}}: {{{returnType}}}{{/returnType}} {{/formatNoEmptyLines}} diff --git a/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautClientCodegenTest.java b/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautClientCodegenTest.java index 7a367f1011..bc13a5a9a4 100644 --- a/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautClientCodegenTest.java +++ b/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautClientCodegenTest.java @@ -397,9 +397,11 @@ void testDiscriminatorConstructorBug() { assertFileContains(apiPath + "BookInfo.kt", """ open class BookInfo( + @field:NotNull @field:JsonProperty(JSON_PROPERTY_NAME) open var name: String, + @field:NotNull @field:JsonProperty(JSON_PROPERTY_TYPE) open var type: BookInfoType? = null, @@ -407,10 +409,12 @@ open class BookInfo( assertFileContains(apiPath + "BasicBookInfo.kt", """ open class BasicBookInfo( + @field:NotNull @field:Size(min = 3) @field:JsonProperty(JSON_PROPERTY_AUTHOR) open var author: String, + @field:NotNull @field:JsonProperty(JSON_PROPERTY_NAME) override var name: String, @@ -419,14 +423,17 @@ open class BasicBookInfo( assertFileContains(apiPath + "DetailedBookInfo.kt", """ data class DetailedBookInfo( + @field:NotNull @field:Pattern(regexp = "[0-9]{13}") @field:JsonProperty(JSON_PROPERTY_ISBN) var isbn: String, + @field:NotNull @field:Size(min = 3) @field:JsonProperty(JSON_PROPERTY_AUTHOR) override var author: String, + @field:NotNull @field:JsonProperty(JSON_PROPERTY_NAME) override var name: String, @@ -622,7 +629,7 @@ void testFileDownloadEndpoint() { assertFileContains(apiPath + "DefaultApi.kt", """ fun fetchData( - @PathVariable("id") @NotNull @Min(0L) id: Long + @PathVariable("id") @NotNull @Min(0L) id: Long, ): Mono>> """); } @@ -754,7 +761,7 @@ void testMultipartFormData() { fun profilePasswordPost( @Header("WCToken") @NotNull wcToken: String, @Header("WCTrustedToken") @NotNull wcTrustedToken: String, - @Body @Nullable multipartBody: MultipartBody? + @Body @Nullable multipartBody: MultipartBody? = null, ): Mono """); } @@ -771,7 +778,7 @@ void testGenerateByMultipleFiles() { @Post("/api/customer/{id}/files") fun uploadFile( @PathVariable("id") @NotNull id: UUID, - @Body @NotNull @Valid fileCreateDto: FileCreateDto + @Body @NotNull @Valid fileCreateDto: FileCreateDto, ): Mono> """); assertFileContains(path + "model/FileCreateDto.kt", @@ -804,22 +811,22 @@ void testMultipleContentTypesEndpoints() { @Post("/multiplecontentpath") @Produces("application/json", "application/xml") fun myOp( - @Body @Nullable @Valid coordinates: Coordinates? + @Body @Nullable @Valid coordinates: Coordinates? = null, ): Mono> """, """ @Post("/multiplecontentpath") @Produces("multipart/form-data") fun myOp_1( - @Nullable @Valid coordinates: Coordinates?, - @Nullable file: ByteArray? + @Nullable @Valid coordinates: Coordinates? = null, + @Nullable file: ByteArray? = null, ): Mono> """, """ @Post("/multiplecontentpath") @Produces("application/yaml", "text/json") fun myOp_2( - @Body @Nullable @Valid mySchema: MySchema? + @Body @Nullable @Valid mySchema: MySchema? = null, ): Mono> """); } @@ -1077,21 +1084,21 @@ void testDeprecated() { description = "A method to send primitives as request parameters", responses = [ ApiResponse(responseCode = "200", description = "Success", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = SendPrimitivesResponse::class)) + Content(mediaType = "application/json", schema = Schema(implementation = SendPrimitivesResponse::class)), ]), - ApiResponse(responseCode = "default", description = "An unexpected error has occurred") + ApiResponse(responseCode = "default", description = "An unexpected error has occurred"), ], parameters = [ Parameter(name = "name", deprecated = true, required = true, `in` = ParameterIn.PATH), Parameter(name = "age", required = true, `in` = ParameterIn.QUERY), - Parameter(name = "height", deprecated = true, required = true, `in` = ParameterIn.HEADER) - ] + Parameter(name = "height", deprecated = true, required = true, `in` = ParameterIn.HEADER), + ], ) @Get("/sendPrimitives/{name}") fun sendPrimitives( @PathVariable("name") @NotNull @java.lang.Deprecated name: String, @QueryValue("age") @NotNull age: BigDecimal, - @Header("height") @NotNull @java.lang.Deprecated height: Float + @Header("height") @NotNull @java.lang.Deprecated height: Float, ): Mono """); @@ -1319,25 +1326,64 @@ void testSwaggerAnnotations() { responses = [ ApiResponse(responseCode = "200", description = "successful operation", content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = Pet::class))), - Content(mediaType = "application/xml", array = ArraySchema(schema = Schema(implementation = Pet::class))) + Content(mediaType = "application/xml", array = ArraySchema(schema = Schema(implementation = Pet::class))), ]), - ApiResponse(responseCode = "400", description = "Invalid status value") + ApiResponse(responseCode = "400", description = "Invalid status value"), ], parameters = [ - Parameter(name = "status", description = "Status values that need to be considered for filter", `in` = ParameterIn.QUERY) + Parameter(name = "status", description = "Status values that need to be considered for filter", `in` = ParameterIn.QUERY), ], security = [ - SecurityRequirement(name = "petstore_auth", scopes = ["write:pets", "read:pets"]) - ] + SecurityRequirement(name = "petstore_auth", scopes = ["write:pets", "read:pets"]), + ], ) @Get("/pet/findByStatus") @Consumes("application/json", "application/xml") fun findPetsByStatus( - @QueryValue("status") @Nullable status: List<@NotNull String>? = null + @QueryValue("status") @Nullable status: List<@NotNull String>? = null, ): Mono> """); } + @Test + void testDiscriminatorOverride() { + + var codegen = new KotlinMicronautClientCodegen(); + codegen.setGenerateSwaggerAnnotations(true); + String outputPath = generateFiles(codegen, "src/test/resources/3_0/test-override-discriminator.yml", CodegenConstants.APIS, CodegenConstants.MODELS); + String path = outputPath + "src/main/kotlin/org/openapitools/"; + + assertFileContains(path + "model/AnimalRequest.kt", + """ + @field:Nullable + @field:Schema(name = "name", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @field:JsonProperty(JSON_PROPERTY_NAME) + @field:JsonInclude(JsonInclude.Include.USE_DEFAULTS) + open var name: String? = null, + + @field:Nullable + @field:Schema(name = "valueType", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @field:JsonProperty(JSON_PROPERTY_VALUE_TYPE) + @field:JsonInclude(JsonInclude.Include.USE_DEFAULTS) + open var valueType: String? = null, + """); + + assertFileContains(path + "model/AnimalResponse.kt", + """ + @field:Nullable + @field:Schema(name = "name", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @field:JsonProperty(JSON_PROPERTY_NAME) + @field:JsonInclude(JsonInclude.Include.USE_DEFAULTS) + open var name: String? = null, + + @field:Nullable + @field:Schema(name = "valueType", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @field:JsonProperty(JSON_PROPERTY_VALUE_TYPE) + @field:JsonInclude(JsonInclude.Include.USE_DEFAULTS) + open var valueType: String? = null, + """); + } + @Test void testEquals() { diff --git a/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautServerCodegenTest.java b/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautServerCodegenTest.java index 946f690845..ea39e2d0da 100644 --- a/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautServerCodegenTest.java +++ b/openapi-generator/src/test/java/io/micronaut/openapi/generator/KotlinMicronautServerCodegenTest.java @@ -608,7 +608,7 @@ fun profilePasswordPost( @Header("WCToken") @NotNull wcToken: String, @Header("WCTrustedToken") @NotNull wcTrustedToken: String, @Part("name") @Nullable name: String?, - @Part("file") @Nullable file: CompletedFileUpload? + @Part("file") @Nullable file: CompletedFileUpload?, ): Mono """); } @@ -625,7 +625,7 @@ void testMultipleContentTypesEndpoints() { @Consumes("application/json", "application/xml") @Secured(SecurityRule.IS_ANONYMOUS) fun myOp( - @Body @Nullable @Valid coordinates: Coordinates? + @Body @Nullable @Valid coordinates: Coordinates?, ): Mono> """, """ @@ -634,7 +634,7 @@ fun myOp( @Secured(SecurityRule.IS_ANONYMOUS) fun myOp_1( @Nullable @Valid coordinates: Coordinates?, - @Nullable file: CompletedFileUpload? + @Nullable file: CompletedFileUpload?, ): Mono> """, """ @@ -642,7 +642,7 @@ fun myOp_1( @Consumes("application/yaml", "text/json") @Secured(SecurityRule.IS_ANONYMOUS) fun myOp_2( - @Body @Nullable @Valid mySchema: MySchema? + @Body @Nullable @Valid mySchema: MySchema?, ): Mono> """); } @@ -694,22 +694,22 @@ void testDeprecated() { description = "A method to send primitives as request parameters", responses = [ ApiResponse(responseCode = "200", description = "Success", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = SendPrimitivesResponse::class)) + Content(mediaType = "application/json", schema = Schema(implementation = SendPrimitivesResponse::class)), ]), - ApiResponse(responseCode = "default", description = "An unexpected error has occurred") + ApiResponse(responseCode = "default", description = "An unexpected error has occurred"), ], parameters = [ Parameter(name = "name", deprecated = true, required = true, `in` = ParameterIn.PATH), Parameter(name = "age", required = true, `in` = ParameterIn.QUERY), - Parameter(name = "height", deprecated = true, required = true, `in` = ParameterIn.HEADER) - ] + Parameter(name = "height", deprecated = true, required = true, `in` = ParameterIn.HEADER), + ], ) @Get("/sendPrimitives/{name}") @Secured(SecurityRule.IS_ANONYMOUS) fun sendPrimitives( @PathVariable("name") @NotNull @java.lang.Deprecated name: String, @QueryValue("age") @NotNull age: BigDecimal, - @Header("height") @NotNull @java.lang.Deprecated height: Float + @Header("height") @NotNull @java.lang.Deprecated height: Float, ): Mono """); } @@ -774,22 +774,22 @@ void testSwaggerAnnotations() { responses = [ ApiResponse(responseCode = "200", description = "successful operation", content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = Pet::class))), - Content(mediaType = "application/xml", array = ArraySchema(schema = Schema(implementation = Pet::class))) + Content(mediaType = "application/xml", array = ArraySchema(schema = Schema(implementation = Pet::class))), ]), - ApiResponse(responseCode = "400", description = "Invalid status value") + ApiResponse(responseCode = "400", description = "Invalid status value"), ], parameters = [ - Parameter(name = "status", description = "Status values that need to be considered for filter", `in` = ParameterIn.QUERY) + Parameter(name = "status", description = "Status values that need to be considered for filter", `in` = ParameterIn.QUERY), ], security = [ - SecurityRequirement(name = "petstore_auth", scopes = ["write:pets", "read:pets"]) - ] + SecurityRequirement(name = "petstore_auth", scopes = ["write:pets", "read:pets"]), + ], ) @Get("/pet/findByStatus") @Produces("application/json", "application/xml") @Secured("write:pets", "read:pets") fun findPetsByStatus( - @QueryValue("status") @Nullable status: List<@NotNull String>? + @QueryValue("status") @Nullable status: List<@NotNull String>?, ): Mono> """); }