Repository: OpenAPITools/openapi-generator (language: python)

Issue:
[REQ] Add x-field-extra-annotation for "kotlin" generator
### Is your feature request related to a problem? Please describe.

Currently java generator (as well as some other generators) has x-field-extra-annotation feature, which allows to annotate Java fileds for any model class, generated from openapi spec. You can find description of x-field-extra-annotation property in openapi-generator docs https://openapi-generator.tech/docs/generators/java/
Currently kotlin generator doesn't support this feature as you can find in docs https://openapi-generator.tech/docs/generators/kotlin/

## Describe the solution you'd like

The request is to add support for x-field-extra-annotation feature for "kotlin" generator. So kotlin models can be generated with additional field annotations. This is especially vital when you need to provide custom <span>@</span>JsonSerialize or JsonDeserialize annotation to deserialize or serialize model correctly. Currently I didn't found any workaround to provide custom JsonSerialize/JsonDeserialize annotations for model fields.

## Describe alternatives you've considered

The only alternative solution I can see so far is to define customized template for kotlin model generator, to manually add support for x-field-extra-annotation attribute.

## Additional context

Here is an example of openapi spec and expected generated model

OpenAPI spec:
```yaml
Account:
  type: "object"
  required:
    - "name"
    - "assets"
  properties:
    name:
      type: "string"
    assets:
      type: "object"
      additionalProperties:
        type: "string"
      x-field-extra-annotation: "@JsonDeserialize(converter = AssetConverter::class)"
```

Generated Model:
```kotlin
data class Account (

    @field:JsonProperty("name")
    val name: kotlin.String,

    @field:JsonProperty("assets")
    @JsonDeserialize(converter = AssetConverter::class)
    val assets: Map<String, String>
)
```




Discussion / hints:
@alex-semenk thanks for the suggestion. May I know if you've time to contribute a PR for that?

@wing328 Sure, I think I might find some time a little later to add the feature. I will let you know when I will have some progress on this.
Hello, is it planned? I see it's available in the documentation: https://openapi-generator.tech/docs/generators/java/
but adding class or field level configs has zero effect
Hi @Oleksii-Hovderchak the documentation you provided is for "java" generator, however current issue is open for "kotlin" generator. For which generator are you missing "x-field-extra-annotation" feature?

Does not support kotlin generator "x-field-extra-annotation"?


unfortunately kotlin is lagging behind :-(
+1
+1
> Hi @Oleksii-Hovderchak the documentation you provided is for "java" generator, however current issue is open for "kotlin" generator. For which generator are you missing "x-field-extra-annotation" feature?

Would it work for kotlin-spring?
The x-... extensions are defined in https://openapi-generator.tech/docs/generators/kotlin-spring/
Just tested on the latest openapi version `id("org.openapi.generator") version "7.9.0"` and this works! Don't know who implemented it but thanks! 
Hi, I've tried to update to latest version `id("org.openapi.generator") version "7.9.0"`, however `x-field-extra-annotation` still doesn't work for me.
I also can't see it in kotlin generator documentation https://openapi-generator.tech/docs/generators/kotlin/
And can't see field being added to mustache templates in repository for kotlin.

@alarv are use sure annotations where added for you to generated classes?
> Hi, I've tried to update to latest version `id("org.openapi.generator") version "7.9.0"`, however `x-field-extra-annotation` still doesn't work for me. I also can't see it in kotlin generator documentation https://openapi-generator.tech/docs/generators/kotlin/ And can't see field being added to mustache templates in repository for kotlin.
> 
> @alarv are use sure annotations where added for you to generated classes?

Hi @alex-semenk, yes it works for me like this:

``` 
     dataObjects:
          type: array
          items:
            $ref: '#/components/schemas/EntitySchema'
          x-field-extra-annotation: "@get:org.mysite.api.service.model.constraints.ValidEntity"
```

@alarv I tried this code but it still doesn't generate annotation for me. The generated code looks like this
```kotlin
@get:JsonProperty("dataObjects")
val dataObjects: kotlin.collections.List<EntitySchema>? = null,
```
@alarv by any chance, maybe you are using `kotlin-spring` generator?
I can see from documentation it supports `x-field-extra-annotation`
https://openapi-generator.tech/docs/generators/kotlin-spring
> @alarv by any chance, maybe you are using `kotlin-spring` generator? I can see from documentation it supports `x-field-extra-annotation` https://openapi-generator.tech/docs/generators/kotlin-spring

Yes, that is correct, sorry about that. 
@alarv no problem at all, let's reopen the issue, I believe I am ready to create PR for this one.
Hi @wing328 I can't see an option to reopen the issue, could I ask you to do it for me?

Fix patch:
diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md
index 82011d0e54b6..7dbee25f2f7e 100644
--- a/docs/generators/kotlin.md
+++ b/docs/generators/kotlin.md
@@ -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 |
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
index 1310e2861912..69258bdf092b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
@@ -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;
@@ -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;
+    }
 }
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
index b6d2b11522f9..394af616a128 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class.mustache
@@ -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}}
@@ -194,7 +197,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
     companion object {
         var openapiFields = HashSet<String>()
         var openapiRequiredFields = HashSet<String>()
-      
+
         init {
             {{#allVars}}
             {{#-first}}
@@ -210,7 +213,7 @@ import {{packageName}}.infrastructure.ITransformForStorage
             openapiRequiredFields.add("{{baseName}}")
             {{/requiredVars}}
         }
-      
+
        /**
         * Validates the JSON Element and throws an exception if issues found
         *
@@ -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]) {
@@ -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))
@@ -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))
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
index 1609fa8656e4..897b18f9e599 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_opt_var.mustache
@@ -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}}
diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
index 3c9387d10151..811867dfc51f 100644
--- a/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
+++ b/modules/openapi-generator/src/main/resources/kotlin-client/data_class_req_var.mustache
@@ -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}}
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiAnnotation.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiAnnotation.kt
index bd33ca92746f..457d2586a3dc 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiAnnotation.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiAnnotation.kt
@@ -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
         *
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiApiResponse.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiApiResponse.kt
index 018bb458a120..b51d977e5208 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiApiResponse.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiApiResponse.kt
@@ -79,7 +79,7 @@ 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")
@@ -87,7 +87,7 @@ data class ApiApiResponse (
             openapiFields.add("message")
 
         }
-      
+
        /**
         * Validates the JSON Element and throws an exception if issues found
         *
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiCategory.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiCategory.kt
index 4d2ab888bb38..38d92229ede2 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiCategory.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiCategory.kt
@@ -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
         *
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiOrder.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiOrder.kt
index af39fc31cfc6..e5bb80c0639e 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiOrder.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiOrder.kt
@@ -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")
@@ -113,7 +113,7 @@ data class ApiOrder (
             openapiFields.add("complete")
 
         }
-      
+
        /**
         * Validates the JSON Element and throws an exception if issues found
         *
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiPet.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiPet.kt
index 35871da8730d..f47705a67d6e 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiPet.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiPet.kt
@@ -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")
@@ -119,7 +119,7 @@ data class ApiPet (
             openapiRequiredFields.add("name")
             openapiRequiredFields.add("photoUrls")
         }
-      
+
        /**
         * Validates the JSON Element and throws an exception if issues found
         *
@@ -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]) {
@@ -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))
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiTag.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiTag.kt
index 8f4b05dcd09d..8418ea6512b7 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiTag.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiTag.kt
@@ -75,14 +75,14 @@ data class ApiTag (
     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
         *
diff --git a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiUser.kt b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiUser.kt
index d47f6636a72a..dc5ff32bd7cd 100644
--- a/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiUser.kt
+++ b/samples/client/petstore/kotlin-model-prefix-type-mappings/src/main/kotlin/org/openapitools/client/models/ApiUser.kt
@@ -100,7 +100,7 @@ data class ApiUser (
     companion object {
         var openapiFields = HashSet<String>()
         var openapiRequiredFields = HashSet<String>()
-      
+
         init {
             // a set of all properties/fields (JSON key names)
             openapiFields.add("username")
@@ -115,7 +115,7 @@ data class ApiUser (
             // a set of required properties/fields (JSON key names)
             openapiRequiredFields.add("username")
         }
-      
+
        /**
         * Validates the JSON Element and throws an exception if issues found
         *
@@ -129,7 +129,7 @@ data class ApiUser (
                 String.format("The required field(s) %s in ApiUser is not found in the empty JSON string", ApiUser.openapiRequiredFields.toString())
               }
             }
-      
+
             // check to make sure all required properties/fields are present in the JSON string
             for (requiredField in openapiRequiredFields) {
               requireNotNull(jsonElement!!.getAsJsonObject()[requiredField]) {


Test patch:
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java
index 9bdbfcb4b544..f3026827af7f 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java
@@ -50,7 +50,7 @@
 @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"))
@@ -58,7 +58,7 @@ private Schema getArrayTestSchema() {
                 .addRequiredItem("id");
     }
 
-    private Schema getSimpleSchema() {
+    private Schema<?> getSimpleSchema() {
         return new ObjectSchema()
                 .description("a sample model")
                 .addProperties("id", new IntegerSchema().format("int64"))
@@ -68,14 +68,14 @@ 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"));
@@ -83,7 +83,7 @@ private Schema getComplexSchema() {
 
     @Test(description = "convert a simple model")
     public void simpleModelTest() {
-        final Schema schema = getSimpleSchema();
+        final Schema<?> schema = getSimpleSchema();
         final DefaultCodegen codegen = new KotlinClientCodegen();
         codegen.processOpts();
 
@@ -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();
@@ -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");
@@ -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();
@@ -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();
@@ -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");
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -448,4 +448,3 @@ private ModelNameTest(String expectedName, String expectedClassName) {
         }
     }
 }
-
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinModelCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinModelCodegenTest.java
index 59e42b4c1c01..dd9bcbf26eb8 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinModelCodegenTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinModelCodegenTest.java
@@ -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 {
 
@@ -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");
+    }
 }