Skip to content

Commit 44a79ac

Browse files
committed
Generate wrappers for oneOf with discriminator when using kotlinx.serialization
1 parent 2c7efda commit 44a79ac

2 files changed

Lines changed: 93 additions & 3 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -974,11 +974,21 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
974974
if (discriminator == null) {
975975
continue;
976976
}
977+
978+
// When using generateOneOfAnyOfWrappers and encountering oneOf, we keep discriminator properties,
979+
// because single entity can be referenced in multiple "parent" entities,
980+
// so discriminator for one might not be discriminator for another.
981+
boolean shouldKeepDiscriminatorField = generateOneOfAnyOfWrappers && cm.oneOf != null && !cm.oneOf.isEmpty();
982+
983+
if (shouldKeepDiscriminatorField) {
984+
continue;
985+
}
986+
977987
// Remove discriminator property from the base class, it is not needed in the generated code
978988
getAllVarProperties(cm).forEach(list -> list.removeIf(var -> var.name.equals(discriminator.getPropertyName())));
979989

980990
for (CodegenDiscriminator.MappedModel mappedModel : discriminator.getMappedModels()) {
981-
// Add the mapping name to additionalProperties.disciminatorValue
991+
// Add the mapping name to additionalProperties.discriminatorValue
982992
// The mapping name is used to define SerializedName, which in result makes derived classes
983993
// found by kotlinx-serialization during deserialization
984994
CodegenProperty additionalProperties = mappedModel.getModel().getAdditionalProperties();
@@ -996,7 +1006,6 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
9961006
mappedModel.getModel().setHasVars(false);
9971007
}
9981008
}
999-
10001009
}
10011010
}
10021011
}

modules/openapi-generator/src/main/resources/kotlin-client/oneof_class.mustache

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ import kotlinx.serialization.builtins.serializer
3737
import kotlinx.serialization.encoding.Decoder
3838
import kotlinx.serialization.encoding.Encoder
3939
{{/enumUnknownDefaultCase}}
40+
{{^enumUnknownDefaultCase}}
41+
{{#generateOneOfAnyOfWrappers}}
42+
{{#discriminator}}
43+
import kotlinx.serialization.KSerializer
44+
import kotlinx.serialization.encoding.Decoder
45+
import kotlinx.serialization.encoding.Encoder
46+
{{/discriminator}}
47+
{{/generateOneOfAnyOfWrappers}}
48+
{{/enumUnknownDefaultCase}}
49+
{{#generateOneOfAnyOfWrappers}}
50+
{{#discriminator}}
51+
import kotlinx.serialization.SerializationException
52+
import kotlinx.serialization.descriptors.SerialDescriptor
53+
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
54+
import kotlinx.serialization.json.JsonDecoder
55+
import kotlinx.serialization.json.JsonEncoder
56+
import kotlinx.serialization.json.JsonObject
57+
import kotlinx.serialization.json.JsonPrimitive
58+
import kotlinx.serialization.json.jsonObject
59+
import kotlinx.serialization.json.jsonPrimitive
60+
{{/discriminator}}
61+
{{/generateOneOfAnyOfWrappers}}
4062
{{#hasEnums}}
4163
{{/hasEnums}}
4264
{{/kotlinx_serialization}}
@@ -57,7 +79,9 @@ import java.io.Serializable
5779
import {{roomModelPackage}}.{{classname}}RoomModel
5880
import {{packageName}}.infrastructure.ITransformForStorage
5981
{{/generateRoomModels}}
82+
{{^kotlinx_serialization}}
6083
import java.io.IOException
84+
{{/kotlinx_serialization}}
6185

6286
/**
6387
* {{{description}}}
@@ -66,12 +90,68 @@ import java.io.IOException
6690
{{#parcelizeModels}}
6791
@Parcelize
6892
{{/parcelizeModels}}
93+
{{^generateOneOfAnyOfWrappers}}
94+
{{^discriminator}}
6995
{{#multiplatform}}{{^discriminator}}@Serializable{{/discriminator}}{{/multiplatform}}{{#kotlinx_serialization}}{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{/serializableModel}}{{/kotlinx_serialization}}{{#moshi}}{{#moshiCodeGen}}@JsonClass(generateAdapter = true){{/moshiCodeGen}}{{/moshi}}{{#jackson}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{/jackson}}
96+
{{/discriminator}}
97+
{{/generateOneOfAnyOfWrappers}}
98+
{{#kotlinx_serialization}}
99+
{{#generateOneOfAnyOfWrappers}}
100+
{{#discriminator}}
101+
@Serializable(with = {{classname}}Serializer::class)
102+
{{/discriminator}}
103+
{{/generateOneOfAnyOfWrappers}}
104+
{{/kotlinx_serialization}}
70105
{{#isDeprecated}}
71106
@Deprecated(message = "This schema is deprecated.")
72107
{{/isDeprecated}}
73108
{{>additionalModelTypeAnnotations}}
109+
{{#kotlinx_serialization}}
110+
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}sealed interface {{classname}} {
111+
{{#discriminator.mappedModels}}
112+
@JvmInline
113+
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}} value class {{modelName}}{{classname}}(val value: {{modelName}}) : {{classname}}
74114

115+
{{/discriminator.mappedModels}}
116+
}
117+
118+
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}object {{classname}}Serializer : KSerializer<{{classname}}> {
119+
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("{{classname}}")
120+
121+
override fun serialize(encoder: Encoder, value: {{classname}}) {
122+
require(encoder is JsonEncoder)
123+
val jsonObject = when (value) {
124+
{{#discriminator.mappedModels}}
125+
is {{classname}}.{{modelName}}{{classname}} -> {
126+
val jsonMap = encoder.json.encodeToJsonElement({{modelName}}.serializer(), value.value).jsonObject.toMutableMap()
127+
jsonMap["{{discriminator.propertyBaseName}}"] = JsonPrimitive("{{mappingName}}")
128+
JsonObject(jsonMap)
129+
}
130+
{{/discriminator.mappedModels}}
131+
}
132+
encoder.encodeJsonElement(jsonObject)
133+
}
134+
135+
override fun deserialize(decoder: Decoder): {{classname}} {
136+
require(decoder is JsonDecoder)
137+
val element = decoder.decodeJsonElement().jsonObject
138+
139+
val discriminatorValue = element["{{discriminator.propertyBaseName}}"]?.jsonPrimitive?.content
140+
?: throw SerializationException("Missing {{discriminator.propertyBaseName}} field")
141+
142+
return when (discriminatorValue) {
143+
{{#discriminator.mappedModels}}
144+
"{{mappingName}}" -> {
145+
val decoded = decoder.json.decodeFromJsonElement({{modelName}}.serializer(), element)
146+
{{classname}}.{{modelName}}{{classname}}(decoded)
147+
}
148+
{{/discriminator.mappedModels}}
149+
else -> throw SerializationException("Unknown {{classname}} {{discriminator.propertyBaseName}}: $discriminatorValue")
150+
}
151+
}
152+
}
153+
{{/kotlinx_serialization}}
154+
{{^kotlinx_serialization}}
75155
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}data class {{classname}}(var actualInstance: Any? = null) {
76156
77157
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}class CustomTypeAdapterFactory : TypeAdapterFactory {
@@ -332,4 +412,5 @@ import java.io.IOException
332412
}
333413
}
334414
}
335-
}
415+
}
416+
{{/kotlinx_serialization}}

0 commit comments

Comments
 (0)