Skip to content
Merged
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
8 changes: 8 additions & 0 deletions docs/generators/kotlin.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useSettingsGradle|Whether the project uses settings.gradle.| |false|
|useSpringBoot3|Whether to use the Spring Boot 3 with the jvm-spring-webclient library.| |false|

## SUPPORTED VENDOR EXTENSIONS

| Extension name | Description | Applicable for | Default value |
| -------------- | ----------- | -------------- | ------------- |
|x-class-extra-annotation|List of custom annotations to be added to model|MODEL|null
|x-field-extra-annotation|List of custom annotations to be added to property|FIELD, OPERATION_PARAMETER|null


## IMPORT MAPPING

| Type/Alias | Imports |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.VendorExtension;
import org.openapitools.codegen.meta.features.ClientModificationFeature;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.meta.features.GlobalFeature;
Expand Down Expand Up @@ -1049,4 +1050,12 @@ public void postProcess() {
System.out.println("# Please support his work directly via https://patreon.com/jimschubert \uD83D\uDE4F #");
System.out.println("################################################################################");
}

@Override
public List<VendorExtension> getSupportedVendorExtensions() {
var extensions = super.getSupportedVendorExtensions();
extensions.add(VendorExtension.X_CLASS_EXTRA_ANNOTATION);
extensions.add(VendorExtension.X_FIELD_EXTRA_ANNOTATION);
return extensions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ import {{packageName}}.infrastructure.ITransformForStorage
@Deprecated(message = "This schema is deprecated.")
{{/isDeprecated}}
{{>additionalModelTypeAnnotations}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
{{#nonPublicApi}}internal {{/nonPublicApi}}{{#discriminator}}interface{{/discriminator}}{{^discriminator}}{{#hasVars}}data {{/hasVars}}class{{/discriminator}} {{classname}}{{^discriminator}} (

{{#allVars}}
Expand Down Expand Up @@ -194,7 +197,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
{{#allVars}}
{{#-first}}
Expand All @@ -210,7 +213,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
openapiRequiredFields.add("{{baseName}}")
{{/requiredVars}}
}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand All @@ -227,7 +230,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
{{^hasChildren}}
{{#requiredVars}}
{{#-first}}

// check to make sure all required properties/fields are present in the JSON string
for (requiredField in openapiRequiredFields) {
requireNotNull(jsonElement!!.getAsJsonObject()[requiredField]) {
Expand All @@ -249,7 +252,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
if (!jsonObj.get("{{{baseName}}}").isJsonArray) {
throw IllegalArgumentException(String.format("Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj["{{{baseName}}}"].toString()))
}

// validate the required field `{{{baseName}}}` (array)
for (i in 0 until jsonObj.getAsJsonArray("{{{baseName}}}").size()) {
{{{items.dataType}}}.validateJsonElement(jsonObj.getAsJsonArray("{{{baseName}}}").get(i))
Expand All @@ -262,7 +265,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
require(jsonObj["{{{baseName}}}"].isJsonArray) {
String.format("Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj["{{{baseName}}}"].toString())
}

// validate the optional field `{{{baseName}}}` (array)
for (i in 0 until jsonObj.getAsJsonArray("{{{baseName}}}").size()) {
{{{items.dataType}}}.validateJsonElement(jsonObj.getAsJsonArray("{{{baseName}}}").get(i))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
{{^isEnum}}{{^isArray}}{{^isPrimitiveType}}{{^isModel}}@Contextual {{/isModel}}{{/isPrimitiveType}}{{/isArray}}{{/isEnum}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
{{/kotlinx_serialization}}
{{/multiplatform}}
{{#vendorExtensions.x-field-extra-annotation}}
{{{vendorExtensions.x-field-extra-annotation}}}
{{/vendorExtensions.x-field-extra-annotation}}
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
{{^isEnum}}{{^isArray}}{{^isPrimitiveType}}{{^isModel}}@Contextual {{/isModel}}{{/isPrimitiveType}}{{/isArray}}{{/isEnum}}@SerialName(value = "{{{vendorExtensions.x-base-name-literal}}}")
{{/kotlinx_serialization}}
{{/multiplatform}}
{{#vendorExtensions.x-field-extra-annotation}}
{{{vendorExtensions.x-field-extra-annotation}}}
{{/vendorExtensions.x-field-extra-annotation}}
{{#deprecated}}
@Deprecated(message = "This property is deprecated.")
{{/deprecated}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@
@SuppressWarnings("static-method")
public class KotlinClientCodegenModelTest {

private Schema getArrayTestSchema() {
private Schema<?> getArrayTestSchema() {
return new ObjectSchema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format("int64"))
.addProperties("examples", new ArraySchema().items(new StringSchema()))
.addRequiredItem("id");
}

private Schema getSimpleSchema() {
private Schema<?> getSimpleSchema() {
return new ObjectSchema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format("int64"))
Expand All @@ -68,22 +68,22 @@ private Schema getSimpleSchema() {
.addRequiredItem("name");
}

private Schema getMapSchema() {
private Schema<?> getMapSchema() {
return new ObjectSchema()
.description("a sample model")
.addProperties("mapping", new MapSchema()
.additionalProperties(new StringSchema()));
}

private Schema getComplexSchema() {
private Schema<?> getComplexSchema() {
return new ObjectSchema()
.description("a sample model")
.addProperties("child", new ObjectSchema().$ref("#/components/schemas/Child"));
}

@Test(description = "convert a simple model")
public void simpleModelTest() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final DefaultCodegen codegen = new KotlinClientCodegen();
codegen.processOpts();

Expand Down Expand Up @@ -128,7 +128,7 @@ public void simpleModelTest() {

@Test(description = "convert a simple model: threetenbp")
public void selectDateLibraryAsThreetenbp() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final KotlinClientCodegen codegen = new KotlinClientCodegen();
codegen.setDateLibrary(KotlinClientCodegen.DateLibrary.THREETENBP.value);
codegen.processOpts();
Expand All @@ -149,7 +149,7 @@ public void selectDateLibraryAsThreetenbp() {

@Test(description = "convert a simple model: threetenbp-localdatetime")
public void selectDateLibraryAsThreetenbpLocalDateTime() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final KotlinClientCodegen codegen = new KotlinClientCodegen();
String value = KotlinClientCodegen.DateLibrary.THREETENBP_LOCALDATETIME.value;
Assert.assertEquals(value, "threetenbp-localdatetime");
Expand All @@ -172,7 +172,7 @@ public void selectDateLibraryAsThreetenbpLocalDateTime() {

@Test(description = "convert a simple model: date string")
public void selectDateLibraryAsString() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final KotlinClientCodegen codegen = new KotlinClientCodegen();
codegen.setDateLibrary(KotlinClientCodegen.DateLibrary.STRING.value);
codegen.processOpts();
Expand All @@ -193,7 +193,7 @@ public void selectDateLibraryAsString() {

@Test(description = "convert a simple model: date java8")
public void selectDateLibraryAsJava8() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final KotlinClientCodegen codegen = new KotlinClientCodegen();
codegen.setDateLibrary(KotlinClientCodegen.DateLibrary.JAVA8.value);
codegen.processOpts();
Expand All @@ -214,7 +214,7 @@ public void selectDateLibraryAsJava8() {

@Test(description = "convert a simple model: date java8-localdatetime")
public void selectDateLibraryAsJava8LocalDateTime() {
final Schema schema = getSimpleSchema();
final Schema<?> schema = getSimpleSchema();
final KotlinClientCodegen codegen = new KotlinClientCodegen();
String value = KotlinClientCodegen.DateLibrary.JAVA8_LOCALDATETIME.value;
Assert.assertEquals(value, "java8-localdatetime");
Expand All @@ -237,7 +237,7 @@ public void selectDateLibraryAsJava8LocalDateTime() {

@Test(description = "convert a model with array property to default kotlin.Array")
public void arrayPropertyTest() {
final Schema model = getArrayTestSchema();
final Schema<?> model = getArrayTestSchema();

final DefaultCodegen codegen = new KotlinClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
Expand All @@ -264,7 +264,7 @@ public void arrayPropertyTest() {

@Test(description = "convert a model with array property to a kotlin.collections.List")
public void listPropertyTest() {
final Schema model = getArrayTestSchema();
final Schema<?> model = getArrayTestSchema();

final KotlinClientCodegen codegen = new KotlinClientCodegen();
codegen.setCollectionType(KotlinClientCodegen.CollectionType.LIST.value);
Expand Down Expand Up @@ -293,7 +293,7 @@ public void listPropertyTest() {

@Test(description = "convert a model with a map property")
public void mapPropertyTest() {
final Schema schema = getMapSchema();
final Schema<?> schema = getMapSchema();
final DefaultCodegen codegen = new KotlinClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", schema);
codegen.setOpenAPI(openAPI);
Expand All @@ -317,7 +317,7 @@ public void mapPropertyTest() {

@Test(description = "convert a model with complex property")
public void complexPropertyTest() {
final Schema schema = getComplexSchema();
final Schema<?> schema = getComplexSchema();
final DefaultCodegen codegen = new KotlinClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", schema);
codegen.setOpenAPI(openAPI);
Expand Down Expand Up @@ -351,7 +351,7 @@ public static Object[][] modelNames() {

@Test(dataProvider = "modelNames", description = "sanitize model names")
public void sanitizeModelNames(final String name, final ModelNameTest testCase) {
final Schema schema = getComplexSchema();
final Schema<?> schema = getComplexSchema();
final DefaultCodegen codegen = new KotlinClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema(name, schema);
codegen.setOpenAPI(openAPI);
Expand Down Expand Up @@ -448,4 +448,3 @@ private ModelNameTest(String expectedName, String expectedClassName) {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.openapitools.codegen.TestUtils.assertFileContains;
import static org.openapitools.codegen.VendorExtension.X_CLASS_EXTRA_ANNOTATION;
import static org.openapitools.codegen.VendorExtension.X_FIELD_EXTRA_ANNOTATION;

public class KotlinModelCodegenTest {

Expand Down Expand Up @@ -110,4 +115,20 @@ public void mutableArrayWithUniqueItems(AbstractKotlinCodegen codegen) throws IO
assertFileContains(Paths.get(outputPath + "/src/main/kotlin/models/UniqueArray.kt"),
"var array: kotlin.collections.MutableSet<kotlin.String>");
}

@Test(dataProvider = "generators")
public void xFieldExtraAnnotation(AbstractKotlinCodegen codegen) throws IOException {
assumeThat(codegen.getSupportedVendorExtensions().contains(X_FIELD_EXTRA_ANNOTATION)).isTrue();
String outputPath = generateModels(codegen, "src/test/resources/3_0/issue_11772.yml", true);
Path ktClassPath = Paths.get(outputPath + "/src/main/kotlin/models/Employee.kt");
assertThat(ktClassPath).content().contains("@javax.persistence.Id");
}

@Test(dataProvider = "generators")
public void xClassExtraAnnotation(AbstractKotlinCodegen codegen) throws IOException {
assumeThat(codegen.getSupportedVendorExtensions().contains(X_CLASS_EXTRA_ANNOTATION)).isTrue();
String outputPath = generateModels(codegen, "src/test/resources/3_0/issue_11772.yml", true);
Path ktClassPath = Paths.get(outputPath + "/src/main/kotlin/models/Employee.kt");
assertThat(ktClassPath).content().contains("@javax.persistence.MappedSuperclass");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ data class ApiAnnotation (
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
// a set of all properties/fields (JSON key names)
openapiFields.add("id")

}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ data class ApiApiResponse (
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
// a set of all properties/fields (JSON key names)
openapiFields.add("code")
openapiFields.add("type")
openapiFields.add("message")

}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ data class ApiCategory (
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
// a set of all properties/fields (JSON key names)
openapiFields.add("id")
openapiFields.add("name")

}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ data class ApiOrder (
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
// a set of all properties/fields (JSON key names)
openapiFields.add("id")
Expand All @@ -113,7 +113,7 @@ data class ApiOrder (
openapiFields.add("complete")

}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ data class ApiPet (
companion object {
var openapiFields = HashSet<String>()
var openapiRequiredFields = HashSet<String>()

init {
// a set of all properties/fields (JSON key names)
openapiFields.add("name")
Expand All @@ -119,7 +119,7 @@ data class ApiPet (
openapiRequiredFields.add("name")
openapiRequiredFields.add("photoUrls")
}

/**
* Validates the JSON Element and throws an exception if issues found
*
Expand All @@ -133,7 +133,7 @@ data class ApiPet (
String.format("The required field(s) %s in ApiPet is not found in the empty JSON string", ApiPet.openapiRequiredFields.toString())
}
}

// check to make sure all required properties/fields are present in the JSON string
for (requiredField in openapiRequiredFields) {
requireNotNull(jsonElement!!.getAsJsonObject()[requiredField]) {
Expand Down Expand Up @@ -161,7 +161,7 @@ data class ApiPet (
require(jsonObj["tags"].isJsonArray) {
String.format("Expected the field `tags` to be an array in the JSON string but got `%s`", jsonObj["tags"].toString())
}

// validate the optional field `tags` (array)
for (i in 0 until jsonObj.getAsJsonArray("tags").size()) {
ApiTag.validateJsonElement(jsonObj.getAsJsonArray("tags").get(i))
Expand Down
Loading