Skip to content

Commit

Permalink
(feat) Polymorphism support for kotlinx serialization
Browse files Browse the repository at this point in the history
Fixes #707. Adds basic polymorphism support to Kotlinx serialization
  • Loading branch information
ctasada committed Apr 20, 2024
1 parent a3198a4 commit a9d4e1f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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
Expand Down Expand Up @@ -60,12 +61,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
Expand Up @@ -89,4 +89,21 @@ 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 a9d4e1f

Please sign in to comment.