2

I'm trying to create a serializer using kotlinx.serialization for Compose Desktop classes, I have this :

@Serializer(forClass = MutableState::class)
class MutableStateSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<MutableState<T>> {
    override fun deserialize(decoder: Decoder) = mutableStateOf(decoder.decodeSerializableValue(dataSerializer))
    override val descriptor: SerialDescriptor = dataSerializer.descriptor
    override fun serialize(encoder: Encoder, value: MutableState<T>) = encoder.encodeSerializableValue(dataSerializer, value.value)
}

That should be used for instances of MutableState class (as the @Serializer annotation says), but I have to put an explicit serializer for each properties otherwise I get this error :

xception in thread "main" kotlinx.serialization.SerializationException: Class 'SnapshotMutableStateImpl' is not registered for polymorphic serialization in the scope of 'MutableState'.
Mark the base class as 'sealed' or register the serializer explicitly

Code used :

@Serializable
class Test {
    var number = mutableStateOf(0)
}

fun main() {
   val json = Json { prettyPrint = true }
   val serialized = json.encodeToString(Test())
   println(serialized)
}

I have to put this annotation on my property :

@Serializable(with = MutableStateSerializer::class)

Isn't there a way to automatically link my serializer to the MutableState interface ? As the SnapshotMutableStateImpl is internal I can't set it to this class.

Ayfri
  • 570
  • 1
  • 4
  • 24

1 Answers1

1

What you want is currently not possible. Other people seem to have requested a feature similar to what you need on GitHub: Global Custom Serializers.

Currently, for 3rd party classes, you need to specify the serializer in one of three ways:

  • Pass the custom serializer to the encode/decode method in case you are serializing it as the root object.
  • Specify the serializer on the property using @Serializable, as you do now.
  • Specify the serializer to be used by a full file using @file:UseSerializers.

Note that due to type inference, number will be attempted to be serialized as the return type of mutableStateOf. If you specify the type as an interface instead (does it have a supertype?), using polymorphic serialization, you could try to register the concrete type and pass your custom serializer there for the concrete type. Not really what this feature is designed for, but I believe it may work if you don't want to specify your serializer in multiple places. However, the serialized form will then include a type discriminator everywhere.

Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161
  • If I use the `@file:UserSerializers` annotation, do I have to put **all** the serializers I need ? Like `String`, `Number` etc. ? Or do I only have to do this for my custom serializers ? – Ayfri Dec 24 '21 at 01:41