https://kotlinlang.org logo
#serialization
Title
# serialization
r

Roman Levinzon

10/06/2023, 12:15 PM
Hello! I’m interested about how Kotlin Serialization works internally, I was hoping some one would help me understand all the ins and outs. Here is what I understand: 1. Some class is marked with
@Serializable
annotation, fx
User.
2. you write
Json.encodeToString(User())
and run the project 3. Compiler generates
UserSerializer
4. Later the
serializer()
function is called that obtains
UserSerializer
using reified type. Here is what I’m missing:
serializer()
function is part of the library. It doesn’t know about any code generated by the compiler. So how would it be able to resolve generated code? In other worlds how this “generated” serialzer gets registered for future use? The reason I’m asking is I’m trying to build a library that works kind of similar to the serialization plugin and it is hard to implement this step. I have KSP that does all steps from 1-3. But really confused about how step 4 would look like Appreciate all the input!
e

ephemient

10/06/2023, 3:08 PM
which
serializer()
function?
@Serialize class Foo
causes the compiler plugin to modify the class so that there is a
Foo.Companion.serializer()
function
the top-level
fun <reified T> serializer<T>()
function is sort of a mix
in some circumstances it uses reflection to find the
.Companion.serializer()
function of the type
but the plugin also implements it as a compiler intrinsic, meaning that it is replaced at compile-time with something else (in this case, a direct reference to the serializer) when possible
(this carries over to the other reified helpers)
you cannot implement that with KSP alone
r

Roman Levinzon

10/06/2023, 3:16 PM
I was talking about that one
Copy code
/**
 * Retrieves a serializer for the given type [T].
 * This overload is a reified version of `serializer(KType)`.
 *
 * This overload works with full type information, including type arguments and nullability,
 * and is a recommended way to retrieve a serializer.
 * For example, `serializer<List<String?>>()` returns [KSerializer] that is able
 * to serialize and deserialize list of nullable strings — i.e. `ListSerializer(String.serializer().nullable)`.
 *
 * Variance of [T]'s type arguments is not used by the serialization and is not taken into account.
 * Star projections in [T]'s type arguments are prohibited.
 *
 * @throws SerializationException if serializer cannot be created (provided [T] or its type argument is not serializable).
 * @throws IllegalArgumentException if any of [T]'s type arguments contains star projection
 */
public inline fun <reified T> serializer(): KSerializer<T> {
    return serializer(typeOf<T>()).cast()
}
I was under the impression that serialization doesn’t use the reflection 👀
e

ephemient

10/06/2023, 3:18 PM
Foo.serializer()
does not use reflection.
serializer<Foo>()
may or may not, depending on compiler/plugin version and switches
r

Roman Levinzon

10/06/2023, 3:19 PM
Would it be possible to modify Companion object using Kotlin Metadata library to achieve the same result? Or custom compiler plugin is only way to go?
e

ephemient

10/06/2023, 3:20 PM
if you're going rewriting the classfiles, anything is possible, but that only applies to JVM
a compiler plugin is the only option if you want it to work in the same compilation or cross-platform though
r

Roman Levinzon

10/06/2023, 3:20 PM
yeah thats fine, not planning to cross-platform
So, If I have a library that kinda mimics the way serialization plugin works. the function to resolve the serializer, lets call it,
mySerializer()
And I want to resolve
UserSerializer
Copy code
val serializer: UserSerializer = mySerializer<User>()
This will only be possible using reflection?
given the
UserSerializer
is generated during KSP processing
3 Views