Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/configs/kotlin-server-jaxrs-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-server
additionalProperties:
useCoroutines: "true"
useTags: "true"
1 change: 1 addition & 0 deletions docs/generators/kotlin-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useCoroutines|Whether to use the Coroutines. This option is currently supported only when using jaxrs-spec library.| |false|
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
|useMutiny|Whether to use Mutiny (should not be used with useCoroutines). This option is currently supported only when using jaxrs-spec library.| |false|
|useTags|use tags for creating interface and controller classnames| |false|

## IMPORT MAPPING

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
public static final String JACKSON2_PACKAGE = "com.fasterxml.jackson";
public static final String JACKSON3_PACKAGE = "tools.jackson";
public static final String JACKSON_PACKAGE = "jacksonPackage";
public static final String USE_TAGS = "useTags";
public static final String USE_TAGS_DESC = "use tags for creating interface and controller classnames";
public static final String SCHEMA_IMPLEMENTS = "schemaImplements";
public static final String SCHEMA_IMPLEMENTS_FIELDS = "schemaImplementsFields";
public static final String X_KOTLIN_IMPLEMENTS_SKIP = "xKotlinImplementsSkip";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.openapitools.codegen.languages;

import com.google.common.collect.ImmutableMap;
import io.swagger.v3.oas.models.Operation;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -64,6 +65,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
private Boolean metricsFeatureEnabled = true;
private boolean interfaceOnly = false;
private boolean useBeanValidation = false;
private boolean useTags = false;
private boolean useCoroutines = false;
private boolean useMutiny = false;
private boolean returnResponse = false;
Expand Down Expand Up @@ -97,6 +99,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
))
.put(Constants.JAXRS_SPEC, Arrays.asList(
USE_BEANVALIDATION,
USE_TAGS,
Constants.USE_COROUTINES,
Constants.USE_MUTINY,
Constants.RETURN_RESPONSE,
Expand Down Expand Up @@ -170,6 +173,7 @@ public KotlinServerCodegen() {
addSwitch(Constants.METRICS, Constants.METRICS_DESC, getMetricsFeatureEnabled());
addSwitch(Constants.INTERFACE_ONLY, Constants.INTERFACE_ONLY_DESC, interfaceOnly);
addSwitch(USE_BEANVALIDATION, Constants.USE_BEANVALIDATION_DESC, useBeanValidation);
addSwitch(USE_TAGS, USE_TAGS_DESC, useTags);
addSwitch(Constants.USE_COROUTINES, Constants.USE_COROUTINES_DESC, useCoroutines);
addSwitch(Constants.USE_MUTINY, Constants.USE_MUTINY_DESC, useMutiny);
addSwitch(Constants.RETURN_RESPONSE, Constants.RETURN_RESPONSE_DESC, returnResponse);
Expand Down Expand Up @@ -241,6 +245,10 @@ public void processOpts() {
setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
}

if (additionalProperties.containsKey(USE_TAGS)) {
useTags = Boolean.parseBoolean(additionalProperties.get(USE_TAGS).toString());
}

if (additionalProperties.containsKey(Constants.OMIT_GRADLE_WRAPPER)) {
setOmitGradleWrapper(Boolean.parseBoolean(additionalProperties.get(Constants.OMIT_GRADLE_WRAPPER).toString()));
}
Expand Down Expand Up @@ -698,6 +706,23 @@ public void postProcess() {
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
OperationMap operations = objs.getOperations();
// For JAXRS_SPEC library, compute commonPath similar to JavaJaxRS generators
if (operations != null && Objects.equals(library, Constants.JAXRS_SPEC)) {
String commonPath = null;
List<CodegenOperation> ops = operations.getOperation();
for (CodegenOperation operation : ops) {
if (commonPath == null) {
commonPath = operation.path;
} else {
commonPath = getCommonPath(commonPath, operation.path);
}
}
for (CodegenOperation co : ops) {
co.path = StringUtils.removeStart(co.path, commonPath);
co.subresourceOperation = co.path.length() > 1;
}
objs.put("commonPath", "/".equals(commonPath) ? StringUtils.EMPTY : commonPath);
}
// The following processing breaks the JAX-RS spec, so we only do this for the other libs.
if (operations != null && !Objects.equals(library, Constants.JAXRS_SPEC)) {
List<CodegenOperation> ops = operations.getOperation();
Expand Down Expand Up @@ -758,6 +783,24 @@ public void setReturnContainer(final String returnContainer) {
return objs;
}

@Override
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
if (Objects.equals(library, Constants.JAXRS_SPEC) && additionalProperties.containsKey(USE_TAGS) && !useTags) {
String basePath = StringUtils.substringBefore(StringUtils.removeStart(resourcePath, "/"), "/");
if (!StringUtils.isEmpty(basePath)) {
co.subresourceOperation = !co.path.isEmpty();
}
co.baseName = basePath;
if (StringUtils.isEmpty(co.baseName) || StringUtils.containsAny(co.baseName, "{", "}")) {
co.baseName = "default";
}
final List<CodegenOperation> opList = operations.computeIfAbsent(co.baseName, k -> new ArrayList<>());
opList.add(co);
} else {
super.addOperationToGroup(tag, resourcePath, operation, co, operations);
}
}

private boolean isJavalin() {
return Constants.JAVALIN5.equals(library) || Constants.JAVALIN6.equals(library);
}
Expand Down Expand Up @@ -788,4 +831,17 @@ private boolean isKtor() {
private boolean isKtor2() {
return Constants.KTOR2.equals(library);
}

private static String getCommonPath(String path1, String path2) {
final String[] parts1 = StringUtils.split(path1, "/");
final String[] parts2 = StringUtils.split(path2, "/");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < Math.min(parts1.length, parts2.length); i++) {
if (!parts1[i].equals(parts2[i])) {
break;
}
builder.append("/").append(parts1[i]);
}
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ All URIs are relative to *{{{basePath}}}*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{{summary}}}
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{#commonPath}}{{commonPath}}{{/commonPath}}{{path}} | {{{summary}}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/generateApiDocs}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {{javaxPackage}}.validation.Valid{{/useBeanValidation}}
@Api(description = "the {{{baseName}}} API"){{/useSwaggerAnnotations}}{{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
@Path("/")
@Path("{{commonPath}}")
{{>generatedAnnotation}}

{{#interfaceOnly}}interface{{/interfaceOnly}}{{^interfaceOnly}}class{{/interfaceOnly}} {{classname}} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static org.openapitools.codegen.TestUtils.assertFileContains;
import static org.openapitools.codegen.TestUtils.assertFileNotContains;
import static org.openapitools.codegen.languages.AbstractKotlinCodegen.USE_JAKARTA_EE;
import static org.openapitools.codegen.languages.AbstractKotlinCodegen.USE_TAGS;
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.*;
import static org.openapitools.codegen.languages.features.BeanValidationFeatures.USE_BEANVALIDATION;

Expand Down Expand Up @@ -509,4 +510,60 @@ public void fixJacksonJsonTypeInfoInheritance_canBeDisabled() throws IOException
"visible = false"
);
}

@Test
public void useTags_commonPathIsComputedForJaxrsSpecLibrary() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinServerCodegen codegen = new KotlinServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(LIBRARY, JAXRS_SPEC);
codegen.additionalProperties().put(USE_TAGS, true);

new DefaultGenerator().opts(new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/2_0/petstore.yaml"))
.config(codegen))
.generate();

String outputPath = output.getAbsolutePath() + "/src/main/kotlin/org/openapitools/server";
Path petApi = Paths.get(outputPath + "/apis/PetApi.kt");

assertFileContains(
petApi,
"@Path(\"/pet\")"
);
assertFileNotContains(
petApi,
"@Path(\"/\")"
);
}

@Test
public void useTags_false_operationsGroupedByPathBaseForJaxrsSpecLibrary() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinServerCodegen codegen = new KotlinServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(LIBRARY, JAXRS_SPEC);
codegen.additionalProperties().put(USE_TAGS, false);

new DefaultGenerator().opts(new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/2_0/petstore.yaml"))
.config(codegen))
.generate();

String outputPath = output.getAbsolutePath() + "/src/main/kotlin/org/openapitools/server";
Path petApi = Paths.get(outputPath + "/apis/PetApi.kt");

assertFileContains(
petApi,
"class PetApi"
);
assertFileNotContains(
petApi,
"class DefaultApi"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import java.io.InputStream



@Path("/")
@Path("")
@jakarta.annotation.Generated(value = arrayOf("org.openapitools.codegen.languages.KotlinServerCodegen"), comments = "Generator version: 7.21.0-SNAPSHOT")
interface StuffApi {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import java.io.InputStream



@Path("/")
@Path("/test/parameters/{path_default}/{path_nullable}")
@javax.annotation.Generated(value = arrayOf("org.openapitools.codegen.languages.KotlinServerCodegen"), comments = "Generator version: 7.21.0-SNAPSHOT")
class DefaultApi {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,46 @@ import java.io.InputStream



@Path("/")
@Path("/pet")
@javax.annotation.Generated(value = arrayOf("org.openapitools.codegen.languages.KotlinServerCodegen"), comments = "Generator version: 7.21.0-SNAPSHOT")
interface PetApi {

@POST
@Path("/pet")
@Path("")
@Consumes("application/json", "application/xml")
fun addPet( body: Pet): io.smallrye.mutiny.Uni<Response>

@DELETE
@Path("/pet/{petId}")
@Path("/{petId}")
fun deletePet(@PathParam("petId") petId: kotlin.Long,@HeaderParam("api_key") apiKey: kotlin.String?): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/pet/findByStatus")
@Path("/findByStatus")
@Produces("application/xml", "application/json")
fun findPetsByStatus(@QueryParam("status") status: kotlin.collections.List<kotlin.String>): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/pet/findByTags")
@Path("/findByTags")
@Produces("application/xml", "application/json")
fun findPetsByTags(@QueryParam("tags") tags: kotlin.collections.List<kotlin.String>): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/pet/{petId}")
@Path("/{petId}")
@Produces("application/xml", "application/json")
fun getPetById(@PathParam("petId") petId: kotlin.Long): io.smallrye.mutiny.Uni<Response>

@PUT
@Path("/pet")
@Path("")
@Consumes("application/json", "application/xml")
fun updatePet( body: Pet): io.smallrye.mutiny.Uni<Response>

@POST
@Path("/pet/{petId}")
@Path("/{petId}")
@Consumes("application/x-www-form-urlencoded")
fun updatePetWithForm(@PathParam("petId") petId: kotlin.Long,@FormParam(value = "name") name: kotlin.String?,@FormParam(value = "status") status: kotlin.String?): io.smallrye.mutiny.Uni<Response>

@POST
@Path("/pet/{petId}/uploadImage")
@Path("/{petId}/uploadImage")
@Consumes("multipart/form-data")
@Produces("application/json")
fun uploadFile(@PathParam("petId") petId: kotlin.Long,@FormParam(value = "additionalMetadata") additionalMetadata: kotlin.String?, @FormParam(value = "file") fileInputStream: InputStream?): io.smallrye.mutiny.Uni<Response>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@ import java.io.InputStream



@Path("/")
@Path("/store")
@javax.annotation.Generated(value = arrayOf("org.openapitools.codegen.languages.KotlinServerCodegen"), comments = "Generator version: 7.21.0-SNAPSHOT")
interface StoreApi {

@DELETE
@Path("/store/order/{orderId}")
@Path("/order/{orderId}")
fun deleteOrder(@PathParam("orderId") orderId: kotlin.String): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/store/inventory")
@Path("/inventory")
@Produces("application/json")
fun getInventory(): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/store/order/{orderId}")
@Path("/order/{orderId}")
@Produces("application/xml", "application/json")
fun getOrderById(@PathParam("orderId") orderId: kotlin.Long): io.smallrye.mutiny.Uni<Response>

@POST
@Path("/store/order")
@Path("/order")
@Produces("application/xml", "application/json")
fun placeOrder( body: Order): io.smallrye.mutiny.Uni<Response>
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,41 @@ import java.io.InputStream



@Path("/")
@Path("/user")
@javax.annotation.Generated(value = arrayOf("org.openapitools.codegen.languages.KotlinServerCodegen"), comments = "Generator version: 7.21.0-SNAPSHOT")
interface UserApi {

@POST
@Path("/user")
@Path("")
fun createUser( body: User): io.smallrye.mutiny.Uni<Response>

@POST
@Path("/user/createWithArray")
@Path("/createWithArray")
fun createUsersWithArrayInput( body: kotlin.collections.List<User>): io.smallrye.mutiny.Uni<Response>

@POST
@Path("/user/createWithList")
@Path("/createWithList")
fun createUsersWithListInput( body: kotlin.collections.List<User>): io.smallrye.mutiny.Uni<Response>

@DELETE
@Path("/user/{username}")
@Path("/{username}")
fun deleteUser(@PathParam("username") username: kotlin.String): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/user/{username}")
@Path("/{username}")
@Produces("application/xml", "application/json")
fun getUserByName(@PathParam("username") username: kotlin.String): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/user/login")
@Path("/login")
@Produces("application/xml", "application/json")
fun loginUser(@QueryParam("username") username: kotlin.String,@QueryParam("password") password: kotlin.String): io.smallrye.mutiny.Uni<Response>

@GET
@Path("/user/logout")
@Path("/logout")
fun logoutUser(): io.smallrye.mutiny.Uni<Response>

@PUT
@Path("/user/{username}")
@Path("/{username}")
fun updateUser(@PathParam("username") username: kotlin.String, body: User): io.smallrye.mutiny.Uni<Response>
}
Loading