[kotlin-spring][server] Feat: Allow implementation of arbitrary interface in DTOs (similar to x-implements from java-spring) (#21950)

* add basic implementation and tests

* improve test a bit

* modify kotlin-spring.md

* add x-kotlin-implements also to enum

* update samples & properly define implemented vendor extension

* use enum.getName() instead of hardcoded string as key in vendor extension map

* fix docs

* fix test openapi spec and test

* add samples for x-kotlin-implements

* add samples for x-kotlin-implements to proper output folder

* fix

* revert unwanted changes

* move to correct place

* fix mustache template

* add to samples-kotlin-server.yaml

* reuse 1 open api schema for everything. Add also case where interface extends interface.

* add warn logs when x-kotlin-implements-fields is used without x-kotlin-implements to improve usability

* remove unnecessary generated files

* remove unnecessary generated files

* remove "status" inner enum from Pet as it fails to properly import as Pet.Status in implementations. This is a separate bug - not caused by x-kotlin-implements
This commit is contained in:
Jachym Metlicka 2025-09-15 20:13:08 +02:00 committed by GitHub
parent 5c04b754ab
commit 6278512122
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
136 changed files with 2650 additions and 97 deletions

View File

@ -38,6 +38,7 @@ jobs:
- samples/server/petstore/kotlin-springboot-source-swagger1
- samples/server/petstore/kotlin-springboot-source-swagger2
- samples/server/petstore/kotlin-springboot-springfox
- samples/server/petstore/kotlin-springboot-x-kotlin-implements
- samples/server/petstore/kotlin-server/ktor
- samples/server/petstore/kotlin-server/ktor2
- samples/server/petstore/kotlin-server/jaxrs-spec

View File

@ -0,0 +1,14 @@
generatorName: kotlin-spring
outputDir: samples/server/petstore/kotlin-springboot-x-kotlin-implements
library: spring-boot
inputSpec: modules/openapi-generator/src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-spring
additionalProperties:
documentationProvider: none
annotationLibrary: none
useSwaggerUI: "false"
serviceImplementation: "false"
skipDefaultInterface: "true"
interfaceOnly: "true"
serializableModel: "true"
beanValidations: "true"

View File

@ -67,6 +67,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|x-discriminator-value|Used with model inheritance to specify value for discriminator that identifies current model|MODEL|
|x-field-extra-annotation|List of custom annotations to be added to property|FIELD, OPERATION_PARAMETER|null
|x-pattern-message|Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable|FIELD, OPERATION_PARAMETER|null
|x-kotlin-implements|Ability to specify interfaces that model must implement|MODEL|empty array
|x-kotlin-implements-fields|Specify attributes that are implemented by the interface(s) added via `x-kotlin-implements`|MODEL|empty array
## IMPORT MAPPING

View File

@ -10,6 +10,8 @@ import java.util.List;
public enum VendorExtension {
X_IMPLEMENTS("x-implements", ExtensionLevel.MODEL, "Ability to specify interfaces that model must implements", "empty array"),
X_KOTLIN_IMPLEMENTS("x-kotlin-implements", ExtensionLevel.MODEL, "Ability to specify interfaces that model must implement", "empty array"),
X_KOTLIN_IMPLEMENTS_FIELDS("x-kotlin-implements-fields", ExtensionLevel.MODEL, "Specify attributes that are implemented by the interface(s) added via `x-kotlin-implements`", "empty array"),
X_SPRING_PAGINATED("x-spring-paginated", ExtensionLevel.OPERATION, "Add `org.springframework.data.domain.Pageable` to controller method. Can be used to handle `page`, `size` and `sort` query parameters. If these query parameters are also specified in the operation spec, they will be removed from the controller method as their values can be obtained from the `Pageable` object.", "false"),
X_SPRING_PROVIDE_ARGS("x-spring-provide-args", ExtensionLevel.OPERATION, "Allows adding additional hidden parameters in the API specification to allow access to content such as header values or properties", "empty array"),
X_DISCRIMINATOR_VALUE("x-discriminator-value", ExtensionLevel.MODEL, "Used with model inheritance to specify value for discriminator that identifies current model", ""),

View File

@ -835,6 +835,16 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
@Override
public CodegenModel fromModel(String name, Schema schema) {
CodegenModel m = super.fromModel(name, schema);
List<String> implementedInterfacesClasses = (List<String>) m.getVendorExtensions().getOrDefault(VendorExtension.X_KOTLIN_IMPLEMENTS.getName(), List.of());
List<String> implementedInterfacesFields = Optional.ofNullable((List<String>) m.getVendorExtensions().get(VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS.getName()))
.map(xKotlinImplementsFields -> {
if (implementedInterfacesClasses.isEmpty() && !xKotlinImplementsFields.isEmpty()) {
LOGGER.warn("Annotating {} with {} without {} is not supported. {} will be ignored.",
name, VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS.getName(), VendorExtension.X_KOTLIN_IMPLEMENTS.getName(),
VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS.getName());
}
return xKotlinImplementsFields;
}).orElse(List.of());
m.optionalVars = m.optionalVars.stream().distinct().collect(Collectors.toList());
// Update allVars/requiredVars/optionalVars with isInherited
// Each of these lists contains elements that are similar, but they are all cloned
@ -850,7 +860,9 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
// Update any other vars (requiredVars, optionalVars)
Stream.of(m.requiredVars, m.optionalVars)
.flatMap(List::stream)
.filter(p -> allVarsMap.containsKey(p.baseName))
.filter(p -> allVarsMap.containsKey(p.baseName)
|| implementedInterfacesFields.contains(p.baseName)
)
.forEach(p -> p.isInherited = true);
return m;
}

View File

@ -1012,6 +1012,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
extensions.add(VendorExtension.X_DISCRIMINATOR_VALUE);
extensions.add(VendorExtension.X_FIELD_EXTRA_ANNOTATION);
extensions.add(VendorExtension.X_PATTERN_MESSAGE);
extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS);
extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS);
return extensions;
}

View File

@ -17,7 +17,34 @@
{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}},
{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>dataClassOptVar}}{{^-last}},
{{/-last}}{{/optionalVars}}
) {{/discriminator}}{{#parent}}: {{{.}}}{{#serializableModel}}, Serializable{{/serializableModel}}{{/parent}}{{^parent}}{{#serializableModel}}: Serializable{{/serializableModel}}{{/parent}}{
){{/discriminator}}{{! no newline
}}{{#parent}} : {{{.}}}{{! no newline
}}{{#serializableModel}}{{! no newline
}}{{^vendorExtensions.x-kotlin-implements}}, Serializable{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{#vendorExtensions.x-kotlin-implements}}, Serializable, {{! no newline
}}{{#-first}} {{{.}}}{{/-first}}{{! no newline
}}{{^-first}}, {{{.}}}{{/-first}}{{! no newline
}}{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{/serializableModel}}{{! no newline
}}{{^serializableModel}}{{! no newline
}}{{#vendorExtensions.x-kotlin-implements}}, {{{.}}}{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{/serializableModel}}{{! no newline
}}{{/parent}}{{! no newline
}}{{^parent}}{{! no newline
}}{{#serializableModel}}{{! no newline
}}{{^vendorExtensions.x-kotlin-implements}} : Serializable{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{#vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{#-first}} : Serializable, {{{.}}}{{/-first}}{{! no newline
}}{{^-first}}, {{{.}}}{{/-first}}{{! no newline
}}{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{/serializableModel}}{{! no newline
}}{{^serializableModel}}{{! no newline
}}{{#vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{#-first}} : {{{.}}}{{/-first}}{{! no newline
}}{{^-first}}, {{{.}}}{{/-first}}{{! no newline
}}{{/vendorExtensions.x-kotlin-implements}}{{! no newline
}}{{/serializableModel}}{{! no newline
}}{{/parent}} {
{{#discriminator}}
{{#requiredVars}}
{{>interfaceReqVar}}{{! prevent indent}}

View File

@ -2,7 +2,7 @@
* {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
enum class {{classname}}(@get:JsonValue val value: {{dataType}}) {
enum class {{classname}}(@get:JsonValue val value: {{dataType}}) {{#vendorExtensions.x-kotlin-implements}}{{#-first}}: {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}} {{/vendorExtensions.x-kotlin-implements}}{
{{#allowableValues}}{{#enumVars}}
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}};

View File

@ -946,10 +946,80 @@ public class KotlinSpringServerCodegenTest {
generator.opts(input).generate();
Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/model/Pet.kt");
assertFileContains(
Paths.get(outputPath + "/src/main/kotlin/org/openapitools/model/Pet.kt"),
path,
"import java.io.Serializable",
") : Serializable{",
") : Serializable {",
"private const val serialVersionUID: kotlin.Long = 1"
);
}
@Test
public void generateSerializableModelWithXimplements() throws Exception {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');
KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(CodegenConstants.SERIALIZABLE_MODEL, true);
ClientOptInput input = new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml"))
.config(codegen);
DefaultGenerator generator = new DefaultGenerator();
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
generator.opts(input).generate();
Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/model/Dog.kt");
assertFileContains(
path,
"import java.io.Serializable",
"@get:JsonProperty(\"likesFetch\", required = true) override val likesFetch: kotlin.Boolean,",
") : Pet, Serializable, com.some.pack.Fetchable {",
"private const val serialVersionUID: kotlin.Long = 1"
);
}
@Test
public void generateNonSerializableModelWithXimplements() throws Exception {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');
KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
ClientOptInput input = new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/kotlin/petstore-with-x-kotlin-implements.yaml"))
.config(codegen);
DefaultGenerator generator = new DefaultGenerator();
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
generator.opts(input).generate();
Path path = Paths.get(outputPath + "/src/main/kotlin/org/openapitools/model/Dog.kt");
assertFileContains(
path,
"@get:JsonProperty(\"likesFetch\", required = true) override val likesFetch: kotlin.Boolean,",
") : Pet, com.some.pack.Fetchable {"
);
assertFileNotContains(
path,
"import java.io.Serializable",
") : Pet, Serializable, com.some.pack.Fetchable {",
") : Pet, Serializable {",
"private const val serialVersionUID: kotlin.Long = 1"
);
}

View File

@ -0,0 +1,646 @@
openapi: 3.0.3
info:
title: OpenAPI Petstore
version: 1.0.0
description: >
This is a sample server Petstore server.
For this sample, you can use the api key `special-key` to test the authorization filters.
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: https://petstore.swagger.io/v2
tags:
- name: pet
description: Everything about your Pets
- name: store
description: Access to Petstore orders
- name: user
description: Operations about user
paths:
/pet:
post:
tags:
- pet
summary: Add a new pet to the store
operationId: addPet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- write:pets
- read:pets
put:
tags:
- pet
summary: Update an existing pet
operationId: updatePet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'400':
description: Invalid ID supplied
'404':
description: Pet not found
'405':
description: Validation exception
security:
- petstore_auth:
- write:pets
- read:pets
/pet/findByStatus:
get:
tags:
- pet
summary: Finds Pets by status
description: Multiple status values can be provided with comma separated strings
operationId: findPetsByStatus
parameters:
- name: status
in: query
description: Status values that need to be considered for filter
required: true
schema:
type: array
items:
type: string
enum:
- available
- pending
- sold
default: [ available ]
style: form
explode: false
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid status value
security:
- petstore_auth:
- write:pets
- read:pets
/pet/findByTags:
get:
tags:
- pet
summary: Finds Pets by tags
description: Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
operationId: findPetsByTags
parameters:
- name: tags
in: query
description: Tags to filter by
required: true
schema:
type: array
items:
type: string
style: form
explode: false
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid tag value
security:
- petstore_auth:
- write:pets
- read:pets
/pet/{petId}:
get:
tags:
- pet
summary: Find pet by ID
description: Returns a single pet
operationId: getPetById
parameters:
- name: petId
in: path
description: ID of pet to return
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid ID supplied
'404':
description: Pet not found
security:
- api_key: [ ]
post:
tags:
- pet
summary: Updates a pet in the store with form data
operationId: updatePetWithForm
requestBody:
required: false
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
name:
type: string
description: Updated name of the pet
status:
type: string
description: Updated status of the pet
parameters:
- name: petId
in: path
description: ID of pet that needs to be updated
required: true
schema:
type: integer
format: int64
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- write:pets
- read:pets
delete:
tags:
- pet
summary: Deletes a pet
operationId: deletePet
parameters:
- name: petId
in: path
description: Pet id to delete
required: true
schema:
type: integer
format: int64
- name: api_key
in: header
required: false
schema:
type: string
responses:
'400':
description: Invalid pet value
security:
- petstore_auth:
- write:pets
- read:pets
/pet/{petId}/uploadImage:
post:
tags:
- pet
summary: Uploads an image
operationId: uploadFile
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
schema:
type: integer
format: int64
requestBody:
required: false
content:
multipart/form-data:
schema:
type: object
properties:
additionalMetadata:
type: string
file:
type: string
format: binary
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
security:
- petstore_auth:
- write:pets
- read:pets
/store/inventory:
get:
tags:
- store
summary: Returns pet inventories by status
operationId: getInventory
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: object
additionalProperties:
type: integer
format: int32
security:
- api_key: [ ]
/store/order:
post:
tags:
- store
summary: Place an order for a pet
operationId: placeOrder
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid Order
/store/order/{orderId}:
get:
tags:
- store
summary: Find purchase order by ID
operationId: getOrderById
parameters:
- name: orderId
in: path
required: true
schema:
type: integer
minimum: 1
maximum: 5
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid ID supplied
'404':
description: Order not found
delete:
tags:
- store
summary: Delete purchase order by ID
operationId: deleteOrder
parameters:
- name: orderId
in: path
required: true
schema:
type: string
responses:
'400':
description: Invalid ID supplied
'404':
description: Order not found
/user:
post:
tags:
- user
summary: Create user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'200':
description: successful operation
/user/createWithArray:
post:
tags:
- user
summary: Creates list of users with given input array
operationId: createUsersWithArrayInput
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
responses:
'200':
description: successful operation
/user/createWithList:
post:
tags:
- user
summary: Creates list of users with given input array
operationId: createUsersWithListInput
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
responses:
'200':
description: successful operation
/user/login:
get:
tags:
- user
summary: Logs user into the system
operationId: loginUser
parameters:
- name: username
in: query
required: true
schema:
type: string
- name: password
in: query
required: true
schema:
type: string
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
headers:
X-Rate-Limit:
schema:
type: integer
X-Expires-After:
schema:
type: string
'400':
description: Invalid username/password supplied
/user/logout:
get:
tags:
- user
summary: Logs out current logged in user session
operationId: logoutUser
responses:
'200':
description: successful operation
/user/{username}:
get:
tags:
- user
summary: Get user by user name
operationId: getUserByName
parameters:
- name: username
in: path
required: true
schema:
type: string
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid username supplied
'404':
description: User not found
put:
tags:
- user
summary: Updated user
operationId: updateUser
parameters:
- name: username
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'400':
description: Invalid user supplied
'404':
description: User not found
delete:
tags:
- user
summary: Delete user
operationId: deleteUser
parameters:
- name: username
in: path
required: true
schema:
type: string
responses:
'400':
description: Invalid username supplied
'404':
description: User not found
components:
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: http://petstore.swagger.io/api/oauth/dialog
scopes:
write:pets: modify pets in your account
read:pets: read your pets
api_key:
type: apiKey
name: api_key
in: header
schemas:
Pet:
type: object
discriminator:
propertyName: petType
mapping:
Dog: '#/components/schemas/Dog'
Cat: '#/components/schemas/Cat'
x-kotlin-implements: [ com.some.pack.Named, com.some.pack.WithCategory, com.some.pack.WithDefaultMethods ]
x-kotlin-implements-fields: [ name, category ]
required:
- name
- photoUrls
- petType
properties:
id:
type: integer
format: int64
category:
$ref: '#/components/schemas/Category'
name:
type: string
photoUrls:
type: array
items:
type: string
tags:
type: array
items:
$ref: '#/components/schemas/Tag'
color:
$ref: '#/components/schemas/Color'
petType:
type: string
Dog:
allOf:
- $ref: '#/components/schemas/Pet'
x-kotlin-implements: [ com.some.pack.Fetchable ]
x-kotlin-implements-fields: [ likesFetch ]
properties:
bark:
type: boolean
breed:
type: string
enum:
- Dingo
- Husky
- Retriever
- Shepherd
likesFetch:
type: boolean
description: Whether the dog enjoys fetching
required: [ bark, breed, likesFetch ]
type: object
Cat:
allOf:
- $ref: '#/components/schemas/Pet'
properties:
hunts:
type: boolean
age:
type: integer
type: object
Category:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
Tag:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
Color:
x-kotlin-implements: [ com.some.pack.WithDefaultMethods ]
type: string
enum:
- black
- white
- brown
- yellow
- violet
Order:
type: object
properties:
id:
type: integer
format: int64
petId:
type: integer
format: int64
quantity:
type: integer
format: int32
shipDate:
type: string
format: date-time
status:
type: string
enum:
- placed
- approved
- delivered
complete:
type: boolean
default: false
User:
type: object
properties:
id:
type: integer
format: int64
username:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
type: string
userStatus:
type: integer
format: int32
ApiResponse:
type: object
properties:
code:
type: integer
format: int32
type:
type: string
message:
type: string

View File

@ -25,7 +25,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -27,7 +27,7 @@ data class ModelApiResponse(
@get:JsonProperty("type") val type: kotlin.String? = null,
@get:JsonProperty("message") val message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -38,7 +38,7 @@ data class Order(
@get:JsonProperty("status") val status: Order.Status? = null,
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -43,7 +43,7 @@ data class Pet(
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -24,7 +24,7 @@ data class Tag(
@get:JsonProperty("id") val id: kotlin.Long? = null,
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -42,7 +42,7 @@ data class User(
@get:JsonProperty("phone") val phone: kotlin.String? = null,
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -22,7 +22,7 @@ data class Annotation(
@Schema(example = "null", description = "")
@get:JsonProperty("id") val id: java.util.UUID? = null
) {
) {
}

View File

@ -79,7 +79,7 @@ data class AnyOfUserOrPet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: AnyOfUserOrPet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -79,7 +79,7 @@ data class AnyOfUserOrPetOrArrayString(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: AnyOfUserOrPetOrArrayString.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -27,7 +27,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -79,7 +79,7 @@ data class UserOrPet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: UserOrPet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -79,7 +79,7 @@ data class UserOrPetOrArrayString(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: UserOrPetOrArrayString.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -25,7 +25,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -27,7 +27,7 @@ data class ModelApiResponse(
@get:JsonProperty("type") val type: kotlin.String? = null,
@get:JsonProperty("message") val message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -38,7 +38,7 @@ data class Order(
@get:JsonProperty("status") val status: Order.Status? = null,
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -43,7 +43,7 @@ data class Pet(
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -24,7 +24,7 @@ data class Tag(
@get:JsonProperty("id") val id: kotlin.Long? = null,
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -42,7 +42,7 @@ data class User(
@get:JsonProperty("phone") val phone: kotlin.String? = null,
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -43,7 +43,7 @@ data class Apa(
@Schema(example = "null", description = "")
@get:JsonProperty("gepa") val gepa: java.math.BigDecimal? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class ApiError(
@field:Valid
@get:JsonProperty("reasonCode") val reasonCode: ReasonCode? = null
) {
) {
/**
*

View File

@ -27,7 +27,7 @@ data class Category(
@Schema(example = "null", description = "")
@get:JsonProperty("name") var name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -31,7 +31,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") var message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -45,7 +45,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") var complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@get:JsonProperty("status") var status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -27,7 +27,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") var name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -51,7 +51,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") var userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -22,7 +22,7 @@ data class MultipartMixedRequestMarker(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class Category(
@get:Pattern(regexp="^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$")
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@Deprecated(message = "")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -32,7 +32,7 @@ import io.swagger.v3.oas.annotations.media.Schema
JsonSubTypes.Type(value = Dog::class, name = "DOG")
)
interface Animal{
interface Animal {
@get:Schema(example = "null", requiredMode = Schema.RequiredMode.REQUIRED, description = "")
val className: kotlin.String

View File

@ -29,7 +29,7 @@ data class Cat(
@Schema(example = "null", description = "")
@get:JsonProperty("color") override val color: kotlin.String? = "red"
) : Animal{
) : Animal {
}

View File

@ -26,7 +26,7 @@ data class Category(
@Schema(example = "null", description = "")
@get:JsonProperty("id") val id: kotlin.Long? = null
) {
) {
}

View File

@ -22,7 +22,7 @@ data class Client(
@Schema(example = "null", description = "")
@get:JsonProperty("client") val client: kotlin.String? = null
) {
) {
}

View File

@ -29,7 +29,7 @@ data class Dog(
@Schema(example = "null", description = "")
@get:JsonProperty("color") override val color: kotlin.String? = "red"
) : Animal{
) : Animal {
}

View File

@ -22,7 +22,7 @@ data class Foo(
@Schema(example = "null", description = "")
@get:JsonProperty("bar") val bar: kotlin.String? = "bar"
) {
) {
}

View File

@ -24,7 +24,7 @@ data class FooGetDefaultResponse(
@field:Valid
@Schema(example = "null", description = "")
@get:JsonProperty("string") val string: Foo? = null
) {
) {
}

View File

@ -30,7 +30,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) {
) {
}

View File

@ -44,7 +44,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) {
) {
/**
* Order Status

View File

@ -48,7 +48,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@get:JsonProperty("status") val status: Pet.Status? = null
) {
) {
/**
* pet status in the store

View File

@ -26,7 +26,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) {
) {
}

View File

@ -50,7 +50,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) {
) {
}

View File

@ -27,7 +27,7 @@ data class Category(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -31,7 +31,7 @@ data class ModelApiResponse(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -45,7 +45,7 @@ data class Order(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@ApiModelProperty(example = "null", value = "pet status in the store")
@get:JsonProperty("status") val status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -27,7 +27,7 @@ data class Tag(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -51,7 +51,7 @@ data class User(
@ApiModelProperty(example = "null", value = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -27,7 +27,7 @@ data class Category(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -31,7 +31,7 @@ data class ModelApiResponse(
@Schema(example = "null", description = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -45,7 +45,7 @@ data class Order(
@Schema(example = "null", description = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@Schema(example = "null", description = "pet status in the store")
@get:JsonProperty("status") val status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -27,7 +27,7 @@ data class Tag(
@Schema(example = "null", description = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -51,7 +51,7 @@ data class User(
@Schema(example = "null", description = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -27,7 +27,7 @@ data class Category(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -31,7 +31,7 @@ data class ModelApiResponse(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("message") val message: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -45,7 +45,7 @@ data class Order(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("complete") val complete: kotlin.Boolean? = false
) : Serializable{
) : Serializable {
/**
* Order Status

View File

@ -49,7 +49,7 @@ data class Pet(
@ApiModelProperty(example = "null", value = "pet status in the store")
@get:JsonProperty("status") val status: Pet.Status? = null
) : Serializable{
) : Serializable {
/**
* pet status in the store

View File

@ -27,7 +27,7 @@ data class Tag(
@ApiModelProperty(example = "null", value = "")
@get:JsonProperty("name") val name: kotlin.String? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -51,7 +51,7 @@ data class User(
@ApiModelProperty(example = "null", value = "User Status")
@get:JsonProperty("userStatus") val userStatus: kotlin.Int? = null
) : Serializable{
) : Serializable {
companion object {
private const val serialVersionUID: kotlin.Long = 1

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,23 @@
README.md
build.gradle.kts
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
gradlew
gradlew.bat
pom.xml
settings.gradle
src/main/kotlin/org/openapitools/api/ApiUtil.kt
src/main/kotlin/org/openapitools/api/Exceptions.kt
src/main/kotlin/org/openapitools/api/PetApi.kt
src/main/kotlin/org/openapitools/api/StoreApi.kt
src/main/kotlin/org/openapitools/api/UserApi.kt
src/main/kotlin/org/openapitools/configuration/EnumConverterConfiguration.kt
src/main/kotlin/org/openapitools/model/Cat.kt
src/main/kotlin/org/openapitools/model/Category.kt
src/main/kotlin/org/openapitools/model/Color.kt
src/main/kotlin/org/openapitools/model/Dog.kt
src/main/kotlin/org/openapitools/model/ModelApiResponse.kt
src/main/kotlin/org/openapitools/model/Order.kt
src/main/kotlin/org/openapitools/model/Pet.kt
src/main/kotlin/org/openapitools/model/Tag.kt
src/main/kotlin/org/openapitools/model/User.kt

View File

@ -0,0 +1,21 @@
# openAPIPetstore
This Kotlin based [Spring Boot](https://spring.io/projects/spring-boot) application has been generated using the [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator).
## Getting Started
This document assumes you have either maven or gradle available, either via the wrapper or otherwise. This does not come with a gradle / maven wrapper checked in.
By default a [`pom.xml`](pom.xml) file will be generated. If you specified `gradleBuildFile=true` when generating this project, a `build.gradle.kts` will also be generated. Note this uses [Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl).
To build the project using maven, run:
```bash
mvn package && java -jar target/openapi-spring-1.0.0.jar
```
To build the project using gradle, run:
```bash
gradle build && java -jar build/libs/openapi-spring-1.0.0.jar
```
If all builds successfully, the server should run on [http://localhost:8080/](http://localhost:8080/)

Some files were not shown because too many files have changed in this diff Show More