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-array-response.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ templateDir: modules/openapi-generator/src/main/resources/kotlin-server
additionalProperties:
interfaceOnly: "true"
useJakartaEe: true
useTags: "true"
1 change: 1 addition & 0 deletions bin/configs/kotlin-server-jaxrs-spec-parameter-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ inputSpec: modules/openapi-generator/src/test/resources/3_0/parameter-test-spec.
templateDir: modules/openapi-generator/src/main/resources/kotlin-server
additionalProperties:
useCoroutines: "true"
useTags: "true"
1 change: 0 additions & 1 deletion bin/configs/kotlin-server-jaxrs-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +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"
implicitHeaders: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,36 @@
package org.openapitools.codegen.languages;

import com.google.common.collect.ImmutableMap;
import io.swagger.v3.oas.models.Operation;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenDiscriminator;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenResponse;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.meta.features.GlobalFeature;
import org.openapitools.codegen.meta.features.ParameterFeature;
import org.openapitools.codegen.meta.features.SchemaSupportFeature;
import org.openapitools.codegen.meta.features.SecurityFeature;
import org.openapitools.codegen.meta.features.WireFormatFeature;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationMap;
Expand All @@ -33,9 +57,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanValidationFeatures {

public static final String DEFAULT_LIBRARY = Constants.KTOR;
Expand Down Expand Up @@ -702,32 +723,45 @@ public void postProcess() {
System.out.println("################################################################################");
}

@Override
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
if (!Objects.equals(library, Constants.JAXRS_SPEC) || useTags) {
super.addOperationToGroup(tag, resourcePath, operation, co, operations);
return;
}

final String basePath = StringUtils.substringBefore(resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath, "/");
if (!StringUtils.isEmpty(basePath)) {
co.subresourceOperation = !co.path.isEmpty();
}
co.baseName = basePath;
if (StringUtils.isEmpty(co.baseName) || co.baseName.chars().anyMatch(ch -> ch == '{' || ch == '}')) {
co.baseName = "default";
}
final List<CodegenOperation> opList = operations.computeIfAbsent(co.baseName, k -> new ArrayList<>());
opList.add(co);
}

@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
OperationMap operations = objs.getOperations();
// For JAXRS_SPEC library, compute commonPath when useTags=true, otherwise default to "/"
// For JAXRS_SPEC library, compute commonPath for all library modes
if (operations != null && Objects.equals(library, Constants.JAXRS_SPEC)) {
if (useTags) {
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);
} else {
for (CodegenOperation co : operations.getOperation()) {
co.subresourceOperation = !co.path.isEmpty();
List<CodegenOperation> ops = operations.getOperation();
// Compute commonPath from operations in this group (called once per API class)
String commonPath = null;
for (CodegenOperation operation : ops) {
if (commonPath == null) {
commonPath = operation.path;
} else {
commonPath = getCommonPath(commonPath, operation.path);
}
objs.put("commonPath", "/");
}
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)) {
Expand Down Expand Up @@ -801,8 +835,8 @@ private boolean isJavalin() {
*/
private boolean usesJacksonSerialization() {
return Constants.JAVALIN5.equals(library) ||
Constants.JAVALIN6.equals(library) ||
Constants.JAXRS_SPEC.equals(library);
Constants.JAVALIN6.equals(library) ||
Constants.JAXRS_SPEC.equals(library);
}

private boolean isKtor2Or3() {
Expand Down
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}}** {{#useTags}}{{commonPath}}{{/useTags}}{{path}} | {{{summary}}}
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{commonPath}}{{path}} | {{{summary}}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/generateApiDocs}}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@{{httpMethod}}
@Path("{{{path}}}"){{#hasConsumes}}
@{{httpMethod}}{{#subresourceOperation}}
@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}
@Consumes({{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}){{/hasConsumes}}{{#hasProduces}}
@Produces({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}){{/hasProduces}}
{{#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}}
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
package org.openapitools.codegen.kotlin;

import lombok.Getter;
import org.antlr.v4.runtime.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.checkerframework.checker.units.qual.C;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.antlr4.KotlinLexer;
import org.openapitools.codegen.antlr4.KotlinParser;
import org.openapitools.codegen.antlr4.KotlinParserBaseListener;
import org.openapitools.codegen.languages.KotlinServerCodegen;
import org.openapitools.codegen.languages.KotlinSpringServerCodegen;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

import static org.openapitools.codegen.CodegenConstants.*;
import static org.openapitools.codegen.CodegenConstants.API_PACKAGE;
import static org.openapitools.codegen.CodegenConstants.LIBRARY;
import static org.openapitools.codegen.CodegenConstants.MODEL_PACKAGE;
import static org.openapitools.codegen.CodegenConstants.PACKAGE_NAME;
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.KotlinServerCodegen.Constants.INTERFACE_ONLY;
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.JAVALIN5;
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.JAVALIN6;
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.JAXRS_SPEC;
import static org.openapitools.codegen.languages.KotlinServerCodegen.Constants.RETURN_RESPONSE;
import static org.openapitools.codegen.languages.features.BeanValidationFeatures.USE_BEANVALIDATION;

public class KotlinServerCodegenTest {
Expand Down Expand Up @@ -222,6 +226,7 @@ public void issue18177Arrays() throws IOException {
codegen.additionalProperties().put(INTERFACE_ONLY, true);
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
codegen.additionalProperties().put(LIBRARY, JAXRS_SPEC);
codegen.additionalProperties().put(USE_TAGS, true);
new DefaultGenerator().opts(new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/kotlin/issue18177-array.yaml"))
.config(codegen))
Expand Down Expand Up @@ -559,9 +564,9 @@ public void useTags_false_classNameFromTagsAndRootPathForJaxrsSpecLibrary() thro

assertFileContains(petApi,
"class PetApi",
"@Path(\"/\")",
"@Path(\"/pet\")",
"@Path(\"/pet/{petId}\")"
"@Path(\"/findByStatus\")",
"@Path(\"/{petId}\")"
);
assertFileNotContains(petApi, "@Path(\"/pet\")".replace("/pet", "/store"));
}
Expand All @@ -586,9 +591,9 @@ public void useTags_notSpecified_behavesLikeUseTagsFalseForJaxrsSpecLibrary() th

assertFileContains(petApi,
"class PetApi",
"@Path(\"/\")",
"@Path(\"/pet\")",
"@Path(\"/pet/{petId}\")"
"@Path(\"/findByStatus\")",
"@Path(\"/{petId}\")"
);
assertFileNotContains(petApi, "@Path(\"/store\")");
}
Expand Down
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.22.0-SNAPSHOT")
interface StuffApi {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ 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.22.0-SNAPSHOT")
class DefaultApi {

@GET
@Path("/test/parameters/{path_default}/{path_nullable}")
suspend fun findPetsByStatus(@PathParam("path_default") pathDefault: kotlin.String,@PathParam("path_nullable") pathNullable: kotlin.String,@QueryParam("query_default") @DefaultValue("available") queryDefault: kotlin.String,@QueryParam("query_default_enum") @DefaultValue("B") queryDefaultEnum: kotlin.String,@QueryParam("query_default_int") @DefaultValue("3") queryDefaultInt: java.math.BigDecimal,@HeaderParam("header_default") @DefaultValue("available") headerDefault: kotlin.String,@HeaderParam("header_default_enum") @DefaultValue("B") headerDefaultEnum: kotlin.String,@HeaderParam("header_default_int") @DefaultValue("3") headerDefaultInt: java.math.BigDecimal,@CookieParam("cookie_default") @DefaultValue("available") cookieDefault: kotlin.String,@CookieParam("cookie_default_enum") @DefaultValue("B") cookieDefaultEnum: kotlin.String,@CookieParam("cookie_default_int") @DefaultValue("3") cookieDefaultInt: java.math.BigDecimal,@QueryParam("query_nullable") queryNullable: kotlin.String?,@HeaderParam("header_nullable") headerNullable: kotlin.String?,@CookieParam("cookie_nullable") cookieNullable: kotlin.String?,@QueryParam("\$query-\$dollar-sign") dollarQueryDollarDollarSign: kotlin.String?): Response {
return Response.ok().entity("magic!").build();
}
Expand Down
40 changes: 20 additions & 20 deletions samples/server/petstore/kotlin-server/jaxrs-spec-mutiny/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,26 @@ All URIs are relative to *http://petstore.swagger.io/v2*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*PetApi* | [**addPet**](docs/PetApi.md#addpet) | **POST** /pet | Add a new pet to the store
*PetApi* | [**deletePet**](docs/PetApi.md#deletepet) | **DELETE** /pet/{petId} | Deletes a pet
*PetApi* | [**findPetsByStatus**](docs/PetApi.md#findpetsbystatus) | **GET** /pet/findByStatus | Finds Pets by status
*PetApi* | [**findPetsByTags**](docs/PetApi.md#findpetsbytags) | **GET** /pet/findByTags | Finds Pets by tags
*PetApi* | [**getPetById**](docs/PetApi.md#getpetbyid) | **GET** /pet/{petId} | Find pet by ID
*PetApi* | [**updatePet**](docs/PetApi.md#updatepet) | **PUT** /pet | Update an existing pet
*PetApi* | [**updatePetWithForm**](docs/PetApi.md#updatepetwithform) | **POST** /pet/{petId} | Updates a pet in the store with form data
*PetApi* | [**uploadFile**](docs/PetApi.md#uploadfile) | **POST** /pet/{petId}/uploadImage | uploads an image
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteorder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
*StoreApi* | [**getInventory**](docs/StoreApi.md#getinventory) | **GET** /store/inventory | Returns pet inventories by status
*StoreApi* | [**getOrderById**](docs/StoreApi.md#getorderbyid) | **GET** /store/order/{orderId} | Find purchase order by ID
*StoreApi* | [**placeOrder**](docs/StoreApi.md#placeorder) | **POST** /store/order | Place an order for a pet
*UserApi* | [**createUser**](docs/UserApi.md#createuser) | **POST** /user | Create user
*UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#createuserswitharrayinput) | **POST** /user/createWithArray | Creates list of users with given input array
*UserApi* | [**createUsersWithListInput**](docs/UserApi.md#createuserswithlistinput) | **POST** /user/createWithList | Creates list of users with given input array
*UserApi* | [**deleteUser**](docs/UserApi.md#deleteuser) | **DELETE** /user/{username} | Delete user
*UserApi* | [**getUserByName**](docs/UserApi.md#getuserbyname) | **GET** /user/{username} | Get user by user name
*UserApi* | [**loginUser**](docs/UserApi.md#loginuser) | **GET** /user/login | Logs user into the system
*UserApi* | [**logoutUser**](docs/UserApi.md#logoutuser) | **GET** /user/logout | Logs out current logged in user session
*UserApi* | [**updateUser**](docs/UserApi.md#updateuser) | **PUT** /user/{username} | Updated user
*PetApi* | [**addPet**](docs/PetApi.md#) | **POST** /pet | Add a new pet to the store
*PetApi* | [**deletePet**](docs/PetApi.md#) | **DELETE** /pet/{petId} | Deletes a pet
*PetApi* | [**findPetsByStatus**](docs/PetApi.md#) | **GET** /pet/findByStatus | Finds Pets by status
*PetApi* | [**findPetsByTags**](docs/PetApi.md#) | **GET** /pet/findByTags | Finds Pets by tags
*PetApi* | [**getPetById**](docs/PetApi.md#) | **GET** /pet/{petId} | Find pet by ID
*PetApi* | [**updatePet**](docs/PetApi.md#) | **PUT** /pet | Update an existing pet
*PetApi* | [**updatePetWithForm**](docs/PetApi.md#) | **POST** /pet/{petId} | Updates a pet in the store with form data
*PetApi* | [**uploadFile**](docs/PetApi.md#) | **POST** /pet/{petId}/uploadImage | uploads an image
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
*StoreApi* | [**getInventory**](docs/StoreApi.md#) | **GET** /store/inventory | Returns pet inventories by status
*StoreApi* | [**getOrderById**](docs/StoreApi.md#) | **GET** /store/order/{orderId} | Find purchase order by ID
*StoreApi* | [**placeOrder**](docs/StoreApi.md#) | **POST** /store/order | Place an order for a pet
*UserApi* | [**createUser**](docs/UserApi.md#) | **POST** /user | Create user
*UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#) | **POST** /user/createWithArray | Creates list of users with given input array
*UserApi* | [**createUsersWithListInput**](docs/UserApi.md#) | **POST** /user/createWithList | Creates list of users with given input array
*UserApi* | [**deleteUser**](docs/UserApi.md#) | **DELETE** /user/{username} | Delete user
*UserApi* | [**getUserByName**](docs/UserApi.md#) | **GET** /user/{username} | Get user by user name
*UserApi* | [**loginUser**](docs/UserApi.md#) | **GET** /user/login | Logs user into the system
*UserApi* | [**logoutUser**](docs/UserApi.md#) | **GET** /user/logout | Logs out current logged in user session
*UserApi* | [**updateUser**](docs/UserApi.md#) | **PUT** /user/{username} | Updated user


<a id="documentation-for-models"></a>
Expand Down
Loading
Loading