cbeust/klaxon

Polymorphic field serialization uses the converter based on the declared field type, not the type of the field value

Opened this issue · 0 comments

Woodz commented
abstract class Animal

class Dog : Animal(val favouritePark: String)

class Cat : Animal(val favouriteWindow: String)

data class PetStore(val cutestAnimal: Animal) 

class DogConverter: Converter {
    override fun canConvert(cls: Class<*>): Boolean = cls == Dog::class.java
    override fun fromJson(jv: JsonValue): Any? = TODO("Not yet implemented")
    override fun toJson(value: Any): String = "Dog!"
}

class CatConverter: Converter {
    override fun canConvert(cls: Class<*>): Boolean = cls == Cat::class.java
    override fun fromJson(jv: JsonValue): Any? = TODO("Not yet implemented")
    override fun toJson(value: Any): String = "Cat!"
}

val petStore = PetStore(Dog("Central"))
val klaxon = Klaxon().converter(DogConverter()).converter(CatConverter())
klaxon.toJsonString(petStore)

Expected: {"cutestAnimal": "Dog!"}
Actual: {"cutestAnimal": {}}

From examine the code, it looks like the declare class type of the property takes precedence over the class of the actual value:
https://github.com/cbeust/klaxon/blob/master/klaxon/src/main/kotlin/com/beust/klaxon/Klaxon.kt#L265

val toConvert = prop?.returnType?.javaType as? Class<*> ?: cls

I don't think this is the best approach as for polymorphic types, typically the specialized converter should be used