kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Include type alias annotations in `SerialDescriptor.annotations`

Open Laxystem opened this issue 1 year ago • 14 comments

I've only seen documentation for .PROPERTY and .CLASS.

Laxystem avatar Jun 05 '24 11:06 Laxystem

No, we currently do not support @SerialInfo-annotations used on types.

sandwwraith avatar Jun 05 '24 12:06 sandwwraith

No, we currently do not support @SerialInfo-annotations used on types.

Ic. Ig this issue has now become a feature request - to support @SerialInfo annotations on TYPE_ALIASes or TYPEs.

Laxystem avatar Jun 05 '24 12:06 Laxystem

To implement this would require updates to SerialDescriptor (in the library) and the compiler plugin. As such it might be helpful to know what your use case is, and what your intended semantics are:

  • For a type alias is the annotation to be understood to be: on the property using the alias; on the class itself; or some third form (note that both of the first two options come with their own challenges)
  • If it is a generic type parameter, how are you going to expose that?

Considering that the serial descriptor is linked to the serializer what you are effectively asking for is some sort of lightweight custom serializer (there is a naming problem here as well - names are supposed to be unique, and some format rely on that fact for caching)

pdvrieze avatar Jun 05 '24 13:06 pdvrieze

As such it might be helpful to know what your use case is, and what your intended semantics are:

public typealias LangString = @NonLinkedJson(wrapWithValueObject = false) @Serializable(with = LangStringSerializer::class) ImmutableMap<Locale?, ImmutableList<String>>

Because it's much more flexible than creating a value class.

If it is a generic type parameter, how are you going to expose that? There is a naming problem here as well - names are supposed to be unique, and some format rely on that fact for caching.

One could support type aliases, instead of types, and then just use the typealias' name.

Laxystem avatar Jun 05 '24 13:06 Laxystem

An alternative would be to support an annotations parameter on SerialDescriptor(serialName: String, original: SerialDescriptor).

Laxystem avatar Jun 05 '24 13:06 Laxystem

@Laxystem You can already use buildSerialDescriptor to build fully custom descriptors (including ones that just copy from the original) - even implementing the interface works (yes I'm aware these are hidden behind experimental flags - this is out of caution, to allow for API changes, not because the feature is going to suddenly disappear). Then you can have (LinkedLangStringSerializer and NonlinkedLangStringSerializer)

pdvrieze avatar Jun 05 '24 14:06 pdvrieze

@Laxystem You can already use buildSerialDescriptor to build fully custom descriptors (including ones that just copy from the original) - even implementing the interface works (yes I'm aware these are hidden behind experimental flags - this is out of caution, to allow for API changes, not because the feature is going to suddenly disappear). Then you can have (LinkedLangStringSerializer and NonlinkedLangStringSerializer)

Ic, thanks. I'll keep this open as a feature request though

Laxystem avatar Jun 08 '24 19:06 Laxystem

The problem with this feature is that in case of usages like

@Serializable
class X

@Serializable
class A(val s: List<@SomeInfo X>, val e: List<@SomeOtherInfo X>)

Serial descriptor for X is not created every time, it is simply taken from X.serializer(), because it is constructed and filled there. It is possible to come up with some technical solution to re-wrap it with some additional annotation info of course, but it is a lot of work for such a narrow-scoped feature

sandwwraith avatar Jun 13 '24 15:06 sandwwraith

Serial descriptor for X is not created every time, it is simply taken from X.serializer(), because it is constructed and filled there. It is possible to come up with some technical solution to re-wrap it with some additional annotation info of course, but it is a lot of work for such a narrow-scoped feature

That's why I'm proposing to support type aliases and not all types.

typealias XWithInfo = @SomeInfo X

// compiles into

typealias XWithInfo = @Serializable(XWithInfoSerializer::class) X

object XWithInfoSerializer : KSerializer<X> by serializer<X>() {
    override val descriptor = [email protected](SomeInfo())
}

// which in turn compiles into replacing all usages of XWithInfo with @Serializable(XWithInfoSerializer::class) X

Laxystem avatar Jun 16 '24 12:06 Laxystem

Type aliases aren't really compiled into anything, they just dissolve into thin air :) I'm not sure if it is possible to provide such substitution with a compiler plugin

sandwwraith avatar Jun 17 '24 10:06 sandwwraith

Type aliases aren't really compiled into anything, they just dissolve into thin air :) I'm not sure if it is possible to provide such substitution with a compiler plugin

That's the thing, what I'm suggesting is to create custom serializers with the typealias' serial name, that way, you have no conflicts.

Laxystem avatar Jun 19 '24 10:06 Laxystem

typealias XWithInfo = @SomeInfo X

// compiles into

typealias XWithInfo = @Serializable(XWithInfoSerializer::class) X

This would be like an extension of MetaSerializable (like the custom/serializer factory behaviour originally discussed when that annotation was introduced).

object XWithInfoSerializer : KSerializer<X> by serializer<X>() {
    override val descriptor = [email protected](SomeInfo())
}

This is not actually valid, the descriptor must have a unique serialName. I'm also not sure that the SomeInfo annotation needs to be attached to the type/serializer rather than the use site.

pdvrieze avatar Jun 20 '24 14:06 pdvrieze

This would be like an extension of MetaSerializable (like the custom/serializer factory behaviour originally discussed when that annotation was introduced). Yes, that was the original idea.

This is not actually valid, the descriptor must have a unique serialName. I'm also not sure that the SomeInfo annotation needs to be attached to the type/serializer rather than the use site.

Yes; and type aliases have a full, unique name, with the package and everything.

Laxystem avatar Jul 22 '24 18:07 Laxystem