Kotlin / kotlinx.serialization

Kotlin multiplatform / multi-format serialization
Apache License 2.0
5.33k stars 618 forks source link

[Question] how can I write a abstract base class to decode ? #2491

Open nesteiner opened 10 months ago

nesteiner commented 10 months ago

hey, sorry to bother you guyes, I have a problem about using abstract base class to serialize

I have such sealed classes

@Serializable
sealed class Frequency {
    @Serializable
    class ByDay(val weekdays: Array<WeekDay>): Frequency()
    @Serializable
    class ByWeek(val count: Int): Frequency()
    @Serializable
    class ByInterval(val count: Int): Frequency()
}

@Serializable
sealed class Goal {
    @Serializable
    object currentDay: Goal()
    @Serializable
    class CurrentAmount(val amount: Int, val unit: String): Goal()
}

I want to define a abstract base class

@JsonComponent
class SealedClassJackson {
    companion object {
        val formmater = Json {
            classDiscriminator = "type"
        }
    }

    class FrequencyDeserializer: JsonDeserializer<Frequency>() {
        override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Frequency {
            val text = p.text
            return formmater.decodeFromString(text)
        }
    }

    class GoalDeserializer: JsonDeserializer<Goal>() {
        override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Goal {
            val text = p.text
            return formatter.decodeFromString(text)
        }
    }
}

there are too many thing duplicated, so I want to define a abstract class so that I can write such code

  abstract class Deserializer<T>: JsonDeserializer<T>() {
        override fun deserialize(p: JsonParser, ctxt: DeserializationContext): T {
            val text = p.text
            return formatter.decodeFromString(text)
        }
    }

class FrequencyDeserializer: Deserializer<Frequency>()
class GoalDeserializer: Deserializer<Goal>()

but there is an error: Cannot use 'T' as reified type parameter. Use a class instead.

how can I fix it

pdvrieze commented 10 months ago

decodeFromString is actually an inline function that takes a reified type parameter. As the type is lost at runtime this must be resolved at compile time. However it is just a shortcut to the version that takes an explicit serializer. As such you'll just need an actual serializer, probably as private/protected member (either in constructor or abstract val).

nesteiner commented 10 months ago

ok, I got it