Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registering multiple contextual serializers for generic class fails #1406

Closed

Conversation

mvdbos
Copy link
Contributor

@mvdbos mvdbos commented Apr 6, 2021

This PR is meant for discussion, not merging.

The use case here is serializing a third party generic class with different contents: ThirdPartyBox.
As is show in the manual, the BoxSerializer in this test is capable of serializing any ThirdPartyBox and takes as its constructor arg the serializer for T.

Different from the examples for generics in the manual, we have to use contextual here, because we don't control ThirdPartyBox.
Unfortunately, adding another contextual serializer for the generic BoxSerializer fails, because SerializersModuleBuilders.registerSerializer() only looks at the toplevel type of generic types to determine if a serializer was already registered.

This is the assertion, see the code for the full setup:

        assertFailsWith(IllegalArgumentException::class) {
            SerializersModule {
                contextual(BoxSerializer(Item.serializer()))
                contextual(BoxSerializer(AnotherItem.serializer()))
            }

        }.also { it.message!!.contains("Serializer for ${ThirdPartyBox::class} already registered in this module") }

As solution could be to add type parameter info as a differentiator to the map, but this would not be possible for JavaScript,
because KClass.typeParameters is not available in JavaScript. How to solve this?

The use case here is serializing a third party generic class with different contents: ThirdPartyBox<T>.
As is show in the manual, the BoxSerializer is capable of serializing any ThirdPartyBox and takes as its constructor arg the
serializer for T.

Different from the examples for generics in the manual, we have to use `contextual` here, because we don't control ThirdPartyBox<T>.
Unfortunately, adding another contextual serializer for the generic BoxSerializer fails, because SerializersModuleBuilders.registerSerializer()
only looks at the toplevel type of generic types to determine if a serializer was already registered.

As solution could be to add type parameter info as a differentiator to the map, but this would not be possible for JavaScript,
because KClass.typeParameters is not available in JavaScript. How to solve this?
@sandwwraith
Copy link
Member

Hi,
We have designed a solution for this, but it is not finished yet. If you take a look at the ContextualSerializer (

private val typeParametersSerializers: Array<KSerializer<*>>
), you find out that it does have additional typeParametersSerializers argument, which is dedicated for, surprise, type arguments of contextually serializable class. As for now plugin provides these arguments, but they're not used. Using this arguments, it is possible to add special function in module builder, that would allow to construct serializer, like that:

SerializersModule {
    contextual<Box> { typeArgs -> BoxSerializer(typeArgs[0]) }
}

@mvdbos
Copy link
Contributor Author

mvdbos commented Apr 13, 2021

Great, that would help. Any idea about ETA?

@sandwwraith
Copy link
Member

@mvdbos No particular guarantees but I hope it would come in one next or two releases

@sandwwraith
Copy link
Member

See here: #1416

@mvdbos
Copy link
Contributor Author

mvdbos commented Apr 15, 2021

@sandwwraith Great! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants