Skip to content

Commit

Permalink
(feat) Polymorphism support for kotlinx serialization
Browse files Browse the repository at this point in the history
Fixes springwolf#707. Adds basic polymorphism support to Kotlinx serialization
  • Loading branch information
ctasada committed Apr 20, 2024
1 parent a3198a4 commit 6fc1871
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import io.swagger.v3.core.converter.ModelConverter
import io.swagger.v3.core.converter.ModelConverterContext
import io.swagger.v3.core.util.RefUtils
import io.swagger.v3.oas.models.media.ArraySchema
import io.swagger.v3.oas.models.media.ComposedSchema
import io.swagger.v3.oas.models.media.MapSchema
import io.swagger.v3.oas.models.media.ObjectSchema
import io.swagger.v3.oas.models.media.Schema
import io.swagger.v3.oas.models.media.StringSchema
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.lang.reflect.ParameterizedType
Expand All @@ -18,6 +20,7 @@ import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaType
import kotlin.reflect.jvm.jvmErasure
import kotlin.reflect.jvm.jvmName

class KotlinxSerializationModelConverter(private val useFqn: Boolean = false) : ModelConverter {

Expand Down Expand Up @@ -60,12 +63,18 @@ class KotlinxSerializationModelConverter(private val useFqn: Boolean = false) :

private fun getPropertySchema(property: KProperty1<*, *>, context: ModelConverterContext): Schema<*> {
val propertySchema: Schema<*>

val name = getPropertyName(property)

val name = getPropertyName(property)
val propertyType = property.returnType.jvmErasure

when {
propertyType.sealedSubclasses.isNotEmpty() -> {
propertySchema = ComposedSchema()
propertyType.sealedSubclasses.forEach { subClass ->
val subSchema = resolveRefSchema(subClass.java, context)
propertySchema.addOneOfItem(subSchema)
}
}

propertyType.isSubclassOf(Collection::class) -> {
propertySchema = ArraySchema()
val value = (property.returnType.javaType as ParameterizedType).actualTypeArguments[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,28 @@ void testClassWithNestedProperty() {
}
}

@Nested
class TestSealedClass {
@Test
void testSealedClassSerialization() {
var result = modelConverters.readAll(new AnnotatedType(ClassWithPolymorphism.class));
assertThat(result).hasSize(3);
assertThat(result.get(Dog.class.getSimpleName())).isNotNull();
assertThat(result.get(Cat.class.getSimpleName())).isNotNull();
assertThat(result.get(Pet.class.getSimpleName())).isNull();

Schema<?> schema = result.get(ClassWithPolymorphism.class.getSimpleName());

final Schema<?> sealedClass = (Schema<?>) schema.getProperties().get("pet");
assertThat(sealedClass).isNotNull();
assertThat(sealedClass.getType()).isNull();
assertThat(sealedClass.get$ref()).isNull();
assertThat(sealedClass.getOneOf()).hasSize(2);
assertThat(sealedClass.getOneOf().get(0).get$ref()).isEqualTo("#/components/schemas/Cat");
assertThat(sealedClass.getOneOf().get(1).get$ref()).isEqualTo("#/components/schemas/Dog");
}
}

@Test
void serializeKotlin() {
final KotlinxSerializationModelConverter modelConverter = new KotlinxSerializationModelConverter();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.springwolf.addons.kotlinx_serialization_model_converter.converter

import io.github.springwolf.addons.kotlinx_serialization_model_converter.converter.ClassWithNestedProperty.NestedClass
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.time.LocalDate
Expand Down Expand Up @@ -89,4 +90,22 @@ data class ClassWithNestedProperty(
val name: String,
val color: Color,
)
}
}

@Serializable
data class ClassWithPolymorphism(
@SerialName("pet")
val pet: Pet,
)


@Serializable
sealed interface Pet

@Serializable
@SerialName("dog")
data class Dog(val bark: Boolean, val breed: String) : Pet

@Serializable
@SerialName("cat")
data class Cat(val hunt: Boolean, val age: Int): Pet

0 comments on commit 6fc1871

Please sign in to comment.