Description
What is your use-case and why do you need this feature?
I want to serialize a type which contains star-projected properties: Survey
below. InputElement
is registered as polymorphic in SerializersModule
and all concrete types are registered as non-generic classes. E.g., Text
.
interface InputElement<TData : Any> { val name: String }
data class Text( override val name: String ) : InputElement<String>
@Serializable
class Survey(
val elements: Set<InputElement<*>>
)
The above is not possible since the compiler plugin warns on the elements
property:
Serializer has not been found for type 'Any'. To use context serializer as fallback, explicitly annotate type or property with @contextual
Note that doing either does not make the error go away. This might be a potential bug, or at least an error message which could be improved.
Interestingly, the following does works:
val elements: Set<InputElement<*>> = setOf( Text( "How do you feel?" ) )
val json = Json { serializersModule = moduleWithPolymorphicInputElement }
val serializer = SetSerializer( PolymorphicSerializer( InputElement::class ) )
val serialized = json.encodeToString( serializer, elements )
val parsed = json.decodeFromString( serializer, serialized )
assertEquals( elements, parsed )
The serializers thus seem capable of doing what I want to do, but I am unable to specify the serializer on the property because of the star-projection.
I also observed serializing Stuff
below works just fine:
@Serializable
sealed class Stuff
{
data class MoreStuff<T : Any>( val input: InputElement<T> ) : Stuff()
}
I am using Kotlin 1.4.31 and serialization 1.1.0.
Describe the solution you'd like
Right now, I think the only way around this is by introducing an intermediate non-generic type which is registered for polymorphic serialization. But, as portrayed in the examples that work, this does not seem necessary.
I also tried specifying a custom serializer for star-projected types: class InputElementSerializer : KSerializer<InputElement<*>>
. But, this gives the same error as above when applied to the type parameter.
Is there a reason this is not allowed, whereas it does seem to work in some cases? Maybe it doesn't really work and I haven't tested enough? I do get weird errors when upgrading to Kotlin 1.5.0 and serialization 1.2.1 which may be related to this use case.