Repository: cjbooms/fabrikt
Pull request #97 (2021-12-06 12:55:56)

Use x-extensible-enum value for json subtype annotation
When the discriminator is an x-extensible-enum, the enum value should be used to select the subtype, not the class name as a string.


Patch:
diff --git a/README.md b/README.md
index 4d33fdf..a5413f0 100644
--- a/README.md
+++ b/README.md
@@ -166,6 +166,7 @@ Here is an example of a Gradle task with code generated to the `build/generated`
 val fabrikt: Configuration by configurations.creating
 
 val generationDir = "$buildDir/generated"
+val apiFile = "$buildDir/path-to-api/open-api.yaml"
 
 sourceSets {
     main { java.srcDirs("$generationDir/src/main/kotlin") }
@@ -176,12 +177,15 @@ sourceSets {
 tasks {   
     ...
     val generateCode by creating(JavaExec::class) {
+        inputs.files(apiFile)
+        outputs.dir(generationDir)
+        outputs.cacheIf { true }
         classpath(fabrikt)
         main = "com.cjbooms.fabrikt.cli.CodeGen"
         args = listOf(
             "--output-directory", generationDir,
             "--base-package", "com.example",
-            "--api-file", "/path-to-api/open-api.yaml",
+            "--api-file", apiFile,
             "--targets", "http_models",
             "--targets", "client",
             "--http-client-opts", "resilience4j"
diff --git a/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonMetadata.kt b/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonMetadata.kt
index 4b4cae3..b9cbcfd 100644
--- a/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonMetadata.kt
+++ b/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonMetadata.kt
@@ -1,5 +1,7 @@
 package com.cjbooms.fabrikt.generators.model
 
+import com.cjbooms.fabrikt.model.KotlinTypeInfo
+import com.cjbooms.fabrikt.util.NormalisedString.pascalCase
 import com.squareup.kotlinpoet.AnnotationSpec
 import com.squareup.kotlinpoet.ClassName
 import com.squareup.kotlinpoet.CodeBlock
@@ -47,13 +49,17 @@ object JacksonMetadata {
         .addMember("visible = true")
         .build()
 
-    fun polymorphicSubTypes(typePairs: Map<String, TypeName>): AnnotationSpec {
+    fun polymorphicSubTypes(typePairs: Map<String, TypeName>, enumDiscriminator: KotlinTypeInfo.Enum?): AnnotationSpec {
         val codeBuilder = CodeBlock.builder()
         typePairs.forEach { (name, type) ->
             if (codeBuilder.isNotEmpty()) codeBuilder.add(",")
+            val maybeSchemaEnumValue = enumDiscriminator?.entries?.firstOrNull {
+                // lowercase to cover UPPER_SNAKE_CASE
+                it.pascalCase() == name || it.toLowerCase().pascalCase() == name
+            }
             codeBuilder.add(
                 "%T.Type(value = %T::class, name = %S)",
-                JSON_SUB_TYPES_CLASS, type, name
+                JSON_SUB_TYPES_CLASS, type, maybeSchemaEnumValue ?: name
             )
         }
 
diff --git a/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonModelGenerator.kt b/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonModelGenerator.kt
index 1ab16c9..55bb7af 100644
--- a/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonModelGenerator.kt
+++ b/src/main/kotlin/com/cjbooms/fabrikt/generators/model/JacksonModelGenerator.kt
@@ -373,7 +373,10 @@ class JacksonModelGenerator(
                 it to toModelType(packages.base, KotlinTypeInfo.from(schemaInfo.schema, schemaInfo.name))
             }
         }.toMap()
-        classBuilder.addAnnotation(polymorphicSubTypes(mappings))
+        val maybeEnumDiscriminator = properties
+            .firstOrNull { it.name == discriminator.propertyName }?.typeInfo as? KotlinTypeInfo.Enum
+
+        classBuilder.addAnnotation(polymorphicSubTypes(mappings, maybeEnumDiscriminator))
             .addQuarkusReflectionAnnotation()
             .addMicronautIntrospectedAnnotation()
 


Test patch:
diff --git a/src/test/resources/examples/oneOfPolymorphicModels/models/Models.kt b/src/test/resources/examples/oneOfPolymorphicModels/models/Models.kt
index ea22280..d89e613 100644
--- a/src/test/resources/examples/oneOfPolymorphicModels/models/Models.kt
+++ b/src/test/resources/examples/oneOfPolymorphicModels/models/Models.kt
@@ -116,9 +116,9 @@ data class PolymorphicTypeTwoB(
     JsonSubTypes.Type(
         value = ChildTypeA::class,
         name =
-        "ChildTypeA"
+        "CHILD_TYPE_A"
     ),
-    JsonSubTypes.Type(value = ChildTypeB::class, name = "ChildTypeB")
+    JsonSubTypes.Type(value = ChildTypeB::class, name = "CHILD_TYPE_B")
 )
 sealed class ParentSpec() {
     abstract val type: ParentType