Skip to content

Support specifying polymorphic serializer for star-projected generic types #1501

Open
@Whathecode

Description

@Whathecode

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions