Consider all Serializable class implements a common interface to get the corresponding KSerializer for that class (and this should be done by the compiler plugin).
@Serializable
data class Test(
val name: String
)
the generated code maybe like this
interface KSerializable<T> { // ignore the dummy name (because Serializable is already taken)
val serializer: KSerializer<T>
}
@Serializable
data class Test(
val name: String
) : KSerializable<Test> {
override val serializer
get() = Test.serializer()
}
For now, one can only serialize (and deserialize) an object like this:
val kotlinMessage = buildKotlinMessage()
val kotlinOut = ProtoBuf.plain.dump(Kotlin.Message.serializer(), kotlinMessage)
A serializer must be passed, so we must know the exactly class type.
By this, one can serialize an object easily:
val kotlinMessage = buildKotlinMessage()
val kotlinOut = ProtoBuf.plain.dump(kotlinMessage.serializer, kotlinMessage)
// or if ProtoBuf takes advantage of this interface, we can also do this
val kotlinOut = ProtoBuf.plain.dump(kotlinMessage)
Which looks much better!
Yeah, this is a great idea but it will work only with non-generic classes because classes with generic parameters have .serializer function which accepts parameters. It could be a useful shorthand, but not a silver bullet for a 'retrieve serializer' problem.
But for generic classes can be used some parameters. For example:
@Serializable(SomeExactSerializer::class)
class ItIsSerializable<SomeClass> {鈥
It is in case of unavailable solving of serializer in compile time or:
@Serializable
class ItIsSerializable<ItIsAlsoaserializable> {鈥
As and for primitives and other built-in serializable types:
@Serializable
class ItIsSerializable<Long> {鈥
For each type will be used interface KSerializable, but in fact its built-in serializer may have any type of generic. Please, correct me if I am wrong.
This would be really useful; it would allow adding extension functions to classes that are serializable
I came here just to ask for it, but for a different purpose: I want to create a type-safe API, that checks at compile-time, whether a class is serializable or not.
For example, say I have a generic function that serializes an object using the experimental KClass.serializer() function (to retrieve the class serializer using Reflection):
fun sendToClient(response: Any) {
...
val json = Json.stringify(response::class.serializer(), response)
...
}
Consumers of this function will be able to call it with not-serializable instances, because it has the Any type.
However, if an interface (like, for example, KSerializable) gets added to every @Serializable-annotated class, then I could rewrite this function as:
fun sendToClient(response: KSerializable) {
...
val json = Json.stringify(response::class.serializer(), response)
...
}
... And, suddenly, compile-time checking! :)
Also, it could be used to further improve the signature of KClass.serializer() from:
fun <T : Any> KClass<T>.serializer(): KSerializer<T> = ...
To:
fun <T : KSerializable> KClass<T>.serializer(): KSerializer<T> = ...
And, suddenly, compile-time checking again.
All proposed use-cases are valid, but unfortunately, this feature cannot be implemented in a way that works all the time consistently.
Classes with type parameters are one part of the problem. E.g. does List<T> implement KSerializable<T>? If so, what should its serializer function return?
Another problem is Kotlin built-in types: primitives, collections, String etc. that obviously cannot implement an interface from the 3rd-party library. All interfaces are implicitly marked with @Polymorphic.
Also, there are 3-rd party classes that are only externally serializable (@Serializer(forClass = ...)).
Taking this into account, it doesn't seem possible to implement this with a reasonable effort. In the future, if Kotlin has typeclasses, it will be possible to solve this problem using them though.
Closing as won't fix.
Most helpful comment
I came here just to ask for it, but for a different purpose: I want to create a type-safe API, that checks at compile-time, whether a class is serializable or not.
For example, say I have a generic function that serializes an object using the experimental
KClass.serializer()function (to retrieve the class serializer using Reflection):Consumers of this function will be able to call it with not-serializable instances, because it has the
Anytype.However, if an interface (like, for example,
KSerializable) gets added to every@Serializable-annotated class, then I could rewrite this function as:... And, suddenly, compile-time checking! :)
Also, it could be used to further improve the signature of
KClass.serializer()from:To:
And, suddenly, compile-time checking again.