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

Make accessible the original descriptor when wrapped into nullable #2631

Open
Chuckame opened this issue Apr 15, 2024 · 3 comments · Fixed by #2633
Open

Make accessible the original descriptor when wrapped into nullable #2631

Chuckame opened this issue Apr 15, 2024 · 3 comments · Fixed by #2633
Labels

Comments

@Chuckame
Copy link
Contributor

Chuckame commented Apr 15, 2024

What is your use-case and why do you need this feature?
I'm currently working for the avro4k library that is the implementation of avro format with this powerful kotlin serialization library.

We need to generate schemas usually more complex than just based on descriptors' kinds. To do that, it was previously done by creating a custom class implementing a SerialDescriptor and add custom methods to generate the schemas according to a custom logic. The main issue with it is that, just for nullable descriptor (with descriptor.nullable done by the plugin), with need to use kotlin reflection to get back the original descriptor because it is a private field. To bypass it, we had to make a complex system that discovers custom annotations and generate a schema according those annotations.

But still, the simplest way would be to just access to the original descriptor. It allows us to decouple the schema generation system from the custom logics inferred by the custom serializers.

Here is the example of what

Describe the solution you'd like
Just make public the original field inside the SerialDescriptorForNullable data class.

A second option would be to have the same extension method as public val SerialDescriptor.capturedKClass: KClass<*>?:

public val SerialDescriptor.unwrapOriginalDescriptor: SerialDescriptor
    get() = when (this) {
        is SerialDescriptorForNullable -> this.original
        else -> this
    }

I can do the PR if needed

@sandwwraith
Copy link
Member

Yes, I think this makes sense, even though we do not encourage implementing SerialDescriptor manually (but we don't prohibit it either).

@Chuckame
Copy link
Contributor Author

To be honest, I don't really like doing this, but I don't have a better idea without doing any reflection, and keep the serializer's and the schema generation together... Since the schema is highly linked to the serializer's descriptor, so when we want to generate a custom schema, then it makes sense to have it close to the descriptor.

When do you think the PR would be merged and released? Do you have a weekly, monthly or quartly releases?

To bypass this, currently, I use buildSerialDescriptor to add a custom annotation providing the object's class of the schema supplier. So the pro is that we can link the schema directly on the descriptor, and the cons is that we need reflection to get the supplier's instance...

Why buildSerialDescriptor is an international api as it allows us to put additional metadata using annotations?

Chuckame added a commit to Chuckame/kotlinx.serialization that referenced this issue Apr 17, 2024
@pdvrieze
Copy link
Contributor

pdvrieze commented Apr 18, 2024

@Chuckame In the development branch of xmlutil I have a similar situation. I made a subtype of KSerializer that would allow for special handling in the format (making the format aware that the serializer treats xml special), this allows for not having to special case certain types (like dom nodes/elements).

These special serializers may use a different descriptor for xml than for the normal serialization flow. This is implemented through a special annotation as marker, and when this annotation is present, the format will then use a negative index to elementSerialDescriptor to get the format specific descriptor. This works because NullableDescriptor doesn't check indices, but directly forwards the index. I would have preferred to just subtype SerialDescriptor and "extract" it from the nullable descriptor. See: https://github.com/pdvrieze/xmlutil/blob/e8af41966b52be72d91cb1cb1eb510f5a3630b04/core/base/src/commonMain/kotlin/nl/adaptivity/xmlutil/XmlSerializer.kt#L44-L50

As an aside, the XML library also uses deep type inspection to construct the structure (before serializing/deserializing it creates a format specific descriptor that actually directs the structure - this is configurable using a policy), you may want to have a look. ( https://github.com/pdvrieze/xmlutil/blob/master/serialization/src/commonMain/kotlin/nl/adaptivity/xmlutil/serialization/structure/XmlDescriptor.kt ). The sharing of the logic between serialization and deserialization also helps with keeping this consistent.

Chuckame added a commit to Chuckame/kotlinx.serialization that referenced this issue Apr 18, 2024
sandwwraith pushed a commit that referenced this issue Apr 18, 2024
…Descriptor.nullable (#2633)

It may be required when a custom class implementing SerialDescriptor is used for schema generation.

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

Successfully merging a pull request may close this issue.

3 participants