Skip to content

Commit ba91cc6

Browse files
authored
[kotlin-server] Fix class names for useTags (#23441)
* Fix class names for useTags = false * Regenerate samples * Default useTags to true and simplify addOperationToGroup for kotlin-server * Enable useTags for all kotlin-server generators * Add a new sample for ktor2 * Fix deserialization for ktor and ktor2 into `Any` and use calendar year
1 parent 9490683 commit ba91cc6

55 files changed

Lines changed: 1550 additions & 183 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bin/configs/kotlin-server-jaxrs-spec.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
55
templateDir: modules/openapi-generator/src/main/resources/kotlin-server
66
additionalProperties:
77
useCoroutines: "true"
8-
useTags: "true"
98
implicitHeaders: "true"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
generatorName: kotlin-server
2+
outputDir: samples/server/petstore/kotlin-server/ktor2-usetags-false
3+
library: ktor2
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-tags.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/kotlin-server
6+
additionalProperties:
7+
hideGenerationTimestamp: "true"
8+
serializableModel: "true"
9+
useTags: "false"

docs/generators/kotlin-server.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
4848
|useCoroutines|Whether to use the Coroutines. This option is currently supported only when using jaxrs-spec library.| |false|
4949
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
5050
|useMutiny|Whether to use Mutiny (should not be used with useCoroutines). This option is currently supported only when using jaxrs-spec library.| |false|
51-
|useTags|use tags for creating interface and controller classnames| |false|
51+
|useTags|use tags for creating interface and controller classnames.| |true|
5252

5353
## IMPORT MAPPING
5454

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
6161
public static final String JACKSON2_PACKAGE = "com.fasterxml.jackson";
6262
public static final String JACKSON3_PACKAGE = "tools.jackson";
6363
public static final String JACKSON_PACKAGE = "jacksonPackage";
64-
public static final String USE_TAGS = "useTags";
65-
public static final String USE_TAGS_DESC = "use tags for creating interface and controller classnames";
6664
public static final String SCHEMA_IMPLEMENTS = "schemaImplements";
6765
public static final String SCHEMA_IMPLEMENTS_FIELDS = "schemaImplementsFields";
6866
public static final String X_KOTLIN_IMPLEMENTS_SKIP = "xKotlinImplementsSkip";

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,35 @@
1717

1818
package org.openapitools.codegen.languages;
1919

20-
import com.google.common.collect.ImmutableMap;
20+
import io.swagger.v3.oas.models.Operation;
21+
import java.io.File;
22+
import java.util.ArrayList;
23+
import java.util.EnumSet;
24+
import java.util.HashMap;
25+
import java.util.HashSet;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.Objects;
29+
import java.util.Set;
2130
import lombok.Getter;
2231
import lombok.Setter;
2332
import org.apache.commons.lang3.StringUtils;
24-
import org.openapitools.codegen.*;
33+
import org.openapitools.codegen.CodegenConstants;
34+
import org.openapitools.codegen.CodegenDiscriminator;
35+
import org.openapitools.codegen.CodegenModel;
36+
import org.openapitools.codegen.CodegenOperation;
37+
import org.openapitools.codegen.CodegenParameter;
38+
import org.openapitools.codegen.CodegenProperty;
39+
import org.openapitools.codegen.CodegenResponse;
40+
import org.openapitools.codegen.CodegenType;
41+
import org.openapitools.codegen.SupportingFile;
2542
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
26-
import org.openapitools.codegen.meta.features.*;
43+
import org.openapitools.codegen.meta.features.DocumentationFeature;
44+
import org.openapitools.codegen.meta.features.GlobalFeature;
45+
import org.openapitools.codegen.meta.features.ParameterFeature;
46+
import org.openapitools.codegen.meta.features.SchemaSupportFeature;
47+
import org.openapitools.codegen.meta.features.SecurityFeature;
48+
import org.openapitools.codegen.meta.features.WireFormatFeature;
2749
import org.openapitools.codegen.model.ModelMap;
2850
import org.openapitools.codegen.model.ModelsMap;
2951
import org.openapitools.codegen.model.OperationMap;
@@ -33,8 +55,7 @@
3355
import org.slf4j.Logger;
3456
import org.slf4j.LoggerFactory;
3557

36-
import java.io.File;
37-
import java.util.*;
58+
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.USE_TAGS;
3859

3960
public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanValidationFeatures {
4061

@@ -64,7 +85,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
6485
private Boolean metricsFeatureEnabled = true;
6586
private boolean interfaceOnly = false;
6687
private boolean useBeanValidation = false;
67-
private boolean useTags = false;
88+
private boolean useTags = true;
6889
private boolean useCoroutines = false;
6990
private boolean useMutiny = false;
7091
private boolean returnResponse = false;
@@ -74,38 +95,6 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
7495
@Setter
7596
private boolean fixJacksonJsonTypeInfoInheritance = true;
7697

77-
// This is here to potentially warn the user when an option is not supported by the target framework.
78-
private Map<String, List<String>> optionsSupportedPerFramework = new ImmutableMap.Builder<String, List<String>>()
79-
.put(Constants.KTOR, Arrays.asList(
80-
Constants.AUTOMATIC_HEAD_REQUESTS,
81-
Constants.CONDITIONAL_HEADERS,
82-
Constants.HSTS,
83-
Constants.CORS,
84-
Constants.COMPRESSION,
85-
Constants.RESOURCES,
86-
Constants.METRICS,
87-
Constants.OMIT_GRADLE_WRAPPER
88-
))
89-
.put(Constants.KTOR2, Arrays.asList(
90-
Constants.AUTOMATIC_HEAD_REQUESTS,
91-
Constants.CONDITIONAL_HEADERS,
92-
Constants.HSTS,
93-
Constants.CORS,
94-
Constants.COMPRESSION,
95-
Constants.RESOURCES,
96-
Constants.METRICS,
97-
Constants.OMIT_GRADLE_WRAPPER
98-
))
99-
.put(Constants.JAXRS_SPEC, Arrays.asList(
100-
USE_BEANVALIDATION,
101-
USE_TAGS,
102-
Constants.USE_COROUTINES,
103-
Constants.USE_MUTINY,
104-
Constants.RETURN_RESPONSE,
105-
Constants.INTERFACE_ONLY
106-
))
107-
.build();
108-
10998
/**
11099
* Constructs an instance of `KotlinServerCodegen`.
111100
*/
@@ -172,7 +161,7 @@ public KotlinServerCodegen() {
172161
addSwitch(Constants.METRICS, Constants.METRICS_DESC, getMetricsFeatureEnabled());
173162
addSwitch(Constants.INTERFACE_ONLY, Constants.INTERFACE_ONLY_DESC, interfaceOnly);
174163
addSwitch(USE_BEANVALIDATION, Constants.USE_BEANVALIDATION_DESC, useBeanValidation);
175-
addSwitch(USE_TAGS, USE_TAGS_DESC, useTags);
164+
addSwitch(USE_TAGS, Constants.USE_TAGS_DESC, useTags);
176165
addSwitch(Constants.USE_COROUTINES, Constants.USE_COROUTINES_DESC, useCoroutines);
177166
addSwitch(Constants.USE_MUTINY, Constants.USE_MUTINY_DESC, useMutiny);
178167
addSwitch(Constants.RETURN_RESPONSE, Constants.RETURN_RESPONSE_DESC, returnResponse);
@@ -405,6 +394,8 @@ public static class Constants {
405394
public static final String IS_KTOR = "isKtor";
406395
public static final String FIX_JACKSON_JSON_TYPE_INFO_INHERITANCE = "fixJacksonJsonTypeInfoInheritance";
407396
public static final String FIX_JACKSON_JSON_TYPE_INFO_INHERITANCE_DESC = "When true (default), ensures Jackson polymorphism works correctly by: (1) always setting visible=true on @JsonTypeInfo, and (2) adding the discriminator property to child models with appropriate default values. When false, visible is only set to true if all children already define the discriminator property.";
397+
public static final String USE_TAGS = "useTags";
398+
public static final String USE_TAGS_DESC = "use tags for creating interface and controller classnames.";
408399
}
409400

410401
@Override
@@ -702,32 +693,40 @@ public void postProcess() {
702693
System.out.println("################################################################################");
703694
}
704695

696+
@Override
697+
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
698+
if (useTags) {
699+
super.addOperationToGroup(tag, resourcePath, operation, co, operations);
700+
return;
701+
}
702+
703+
String basePath = StringUtils.substringBefore(resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath, "/");
704+
if (StringUtils.isEmpty(basePath) || basePath.chars().anyMatch(ch -> ch == '{' || ch == '}')) {
705+
basePath = "default";
706+
}
707+
super.addOperationToGroup(basePath, resourcePath, operation, co, operations);
708+
}
709+
705710
@Override
706711
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
707712
OperationMap operations = objs.getOperations();
708-
// For JAXRS_SPEC library, compute commonPath when useTags=true, otherwise default to "/"
713+
// For JAXRS_SPEC library, compute commonPath for all library modes
709714
if (operations != null && Objects.equals(library, Constants.JAXRS_SPEC)) {
710-
if (useTags) {
711-
String commonPath = null;
712-
List<CodegenOperation> ops = operations.getOperation();
713-
for (CodegenOperation operation : ops) {
714-
if (commonPath == null) {
715-
commonPath = operation.path;
716-
} else {
717-
commonPath = getCommonPath(commonPath, operation.path);
718-
}
719-
}
720-
for (CodegenOperation co : ops) {
721-
co.path = StringUtils.removeStart(co.path, commonPath);
722-
co.subresourceOperation = co.path.length() > 1;
723-
}
724-
objs.put("commonPath", "/".equals(commonPath) ? StringUtils.EMPTY : commonPath);
725-
} else {
726-
for (CodegenOperation co : operations.getOperation()) {
727-
co.subresourceOperation = !co.path.isEmpty();
715+
List<CodegenOperation> ops = operations.getOperation();
716+
// Compute commonPath from operations in this group (called once per API class)
717+
String commonPath = null;
718+
for (CodegenOperation operation : ops) {
719+
if (commonPath == null) {
720+
commonPath = operation.path;
721+
} else {
722+
commonPath = getCommonPath(commonPath, operation.path);
728723
}
729-
objs.put("commonPath", "/");
730724
}
725+
for (CodegenOperation co : ops) {
726+
co.path = StringUtils.removeStart(co.path, commonPath);
727+
co.subresourceOperation = co.path.length() > 1;
728+
}
729+
objs.put("commonPath", "/".equals(commonPath) ? StringUtils.EMPTY : commonPath);
731730
}
732731
// The following processing breaks the JAX-RS spec, so we only do this for the other libs.
733732
if (operations != null && !Objects.equals(library, Constants.JAXRS_SPEC)) {
@@ -801,8 +800,8 @@ private boolean isJavalin() {
801800
*/
802801
private boolean usesJacksonSerialization() {
803802
return Constants.JAVALIN5.equals(library) ||
804-
Constants.JAVALIN6.equals(library) ||
805-
Constants.JAXRS_SPEC.equals(library);
803+
Constants.JAVALIN6.equals(library) ||
804+
Constants.JAXRS_SPEC.equals(library);
806805
}
807806

808807
private boolean isKtor2Or3() {

modules/openapi-generator/src/main/resources/kotlin-server/README.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ All URIs are relative to *{{{basePath}}}*
3535

3636
Class | Method | HTTP request | Description
3737
------------ | ------------- | ------------- | -------------
38-
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{#useTags}}{{commonPath}}{{/useTags}}{{path}} | {{{summary}}}
38+
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{commonPath}}{{path}} | {{{summary}}}
3939
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
4040
{{/generateApiDocs}}
4141

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
@{{httpMethod}}
2-
@Path("{{{path}}}"){{#hasConsumes}}
1+
@{{httpMethod}}{{#subresourceOperation}}
2+
@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}
33
@Consumes({{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}){{/hasConsumes}}{{#hasProduces}}
44
@Produces({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}){{/hasProduces}}
55
{{#useCoroutines}}suspend {{/useCoroutines}}fun {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}){{#returnResponse}}: {{#useMutiny}}io.smallrye.mutiny.Uni<{{/useMutiny}}Response{{#useMutiny}}>{{/useMutiny}}{{/returnResponse}}{{^returnResponse}}{{#returnType}}: {{#useMutiny}}io.smallrye.mutiny.Uni<{{/useMutiny}}{{{returnType}}}{{#useMutiny}}>{{/useMutiny}}{{/returnType}}{{/returnResponse}}{{^returnResponse}}{{^returnType}}{{#useMutiny}}: io.smallrye.mutiny.Uni<Void>{{/useMutiny}}{{/returnType}}{{/returnResponse}}

modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/api.mustache

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import {{packageName}}.infrastructure.ApiPrincipal
2222

2323
{{#operations}}
2424
fun Route.{{classname}}() {
25-
val empty = mutableMapOf<String, Any?>()
26-
2725
{{#operation}}
2826
{{#hasAuthMethods}}
2927
{{#authMethods}}

modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/logback.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<configuration>
22
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
33
<encoder>
4-
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
4+
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
55
</encoder>
66
</appender>
77

modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor2/_response.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ val exampleContentType = "{{{contentType}}}"
22
val exampleContentString = """{{&example}}"""
33

44
when (exampleContentType) {
5-
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
5+
"application/json" -> call.respond(gson.fromJson(exampleContentString, Any::class.java))
66
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
77
else -> call.respondText(exampleContentString)
88
}

0 commit comments

Comments
 (0)