0

I'm developing a small library that defines some domain objects as sealed class objects and I'd like to serialize those objects as simple Strings using the kotlinx-serialization library.

The structure of the sealed class with its objects is something like this:

sealed class Domain(val position: UInt, val name: String)

object DomainA : Domain(0u, "Domain A")
object DomainB : Domain(1u, "Domain B")
object DomainC : Domain(2u, "Domain C")

There are more properties inside the objects but they're irrelevant for this question. The other point is that I'm using this sealed class structure to limit the type usage in my domain models with generics. That's why I'm not using simple Enum constants.

To serialize these objects as Strings, as if they were Enum constants, I'm doing the following:

  • Adding a new property serialName to the object's constructor;
sealed class Domain(val position: UInt, val name: String, val serialName: String)

object DomainA : Domain(0u, "Domain A", "domain-a")
object DomainB : Domain(1u, "Domain B", "domain-b")
object DomainC : Domain(2u, "Domain C", "domain-c")
  • Implementing a fromSerialName() method to find the appropriate instance in the companion object;
fun fromSerialName(serialName: String): Domain? {
    return values.firstOrNull { it.serialName.uppercase() == serialName.trim().uppercase() }
}

This values field is a listOf() all Domain objects that I have to manually update just because of this method.

  • Implementing a custom KSerializer to handle the serialization process.
object DomainSerializer : KSerializer<Domain> {

    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Domain", PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): Domain {
        return Domain.fromSerialName(decoder.decodeString())
    }

    override fun serialize(encoder: Encoder, value: Domain) {
        encoder.encodeString(value.serialName)
    }
}

The whole point of this question is: Is there any way to do this without all this overhead and make the plugin generate this for me? I'd like to do something like:

@Serializable(with = StringSerializer::class) // or some EnumSerializer::class
sealed class Domain(val position: UInt, val name: String)

@SerialName("domain-a") object DomainA : Domain(0u, "Domain A")
@SerialName("domain-b") object DomainB : Domain(1u, "Domain B")
@SerialName("domain-c") object DomainC : Domain(2u, "Domain C")
Daniel Schröder
  • 547
  • 4
  • 18
  • *I'm using this sealed class structure to limit the type usage in my domain models with generics* - could you please elaborate on this point? What does this approach allow you to do exactly? Since you don't have any hierarchy (only objects extending the root sealed class), it's not obvious to me what you can do with those types that you cannot do with enum values – Joffrey Mar 13 '23 at 15:54
  • @Joffrey I'm trying to use those types for validation purposes in compile time. Say I've some other objects defined based on that "Domain" type. Something like "sealed class Other" with objects like "object OtherA : Other" and "object OtherB : Other". This is just an example, as I've a small list of possibilities for each one of those "Domain". With this, I can always be sure to have a valid "Other" object based on the "Domain" type required in my functions. – Daniel Schröder Mar 13 '23 at 17:28
  • Your code as shown isn’t doing anything that couldn’t be done with enums, which would be easier to work with. – Tenfour04 Mar 13 '23 at 21:48
  • @DanielSchröder it would be interesting if you could share code (maybe by editing the question) making use of the fact that those are different types. Even with your explanation in comments, it's hard to tell practically how you use this and why it's important. On the other hand, the need to serialize those things to simple string values really makes it look like it should be enum values. – Joffrey Mar 13 '23 at 23:03

0 Answers0