Kotlinx JSON serialization based on experimental APIs?

I recently took a look at kotlinx-serialization to move from Kryo to a “pure kotlin” serialization library. The Json one is is the only serialization format advertised as “stable” for kotlinx-serialization.

The source code of Json.kt contains the experimental API marker:

public sealed class Json(internal val configuration: JsonConf) : StringFormat {

…and througout the docs, the following functions are used…

val string = Json.encodeToString(data)  
val obj = Json.decodeFromString<Project>(string)

which are defined like this

public inline fun <reified T> Json.encodeToJsonElement(value: T): JsonElement {
    return encodeToJsonElement(serializersModule.serializer(), value)

, i.e. use the extension function SerializersModule.serializer()

public inline fun <reified T> SerializersModule.serializer(): KSerializer<T> {
    return serializer(typeOf<T>()).cast()

… which uses typeOf<T>(), which in turn I believe is marked as experimental.

So, how come that the JSON serialization library is advertised as stable, if it uses experimental features?

What ultimatively held me from migrating to this library, for now, was however, that I was unable to properly encapsulate the serializer in a wrapper class that implements a simple interface that would look something like this…

interface Serializer {
    fun <T> encode(obj: T): String
    fun <T> decode(string: String): T

… because encodeToJsonElement etc. are inline functions with a reified T and thus don’t fit into that.
I also failed to specify the interface with an additional type parameter (fun <T> decode(string: String, KType<T>): T), though I am sorry I don’t remember why this did not work, I’ll probably try again once the JSON serialization API is stable.

The reason to encapsulate the concrete serializer implementation in an interface like this is so that classes that use serialization are not strongly coupled to the specific serialization library but instead just get injected a Serializer and don’t need to care about which format it is or which library is used for that etc.

In Kotlin @ExperimentalSomething usually means “no guarantee of backward compatibility”, not “full of bugs”.

@ExperimentalSerializationApi docs:

Marks declarations that are still experimental in kotlinx.serialization, which means that the design of the corresponding declarations has open issues which may (or may not) lead to their changes in the future.
Roughly speaking, there is a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change in some way that may break some code.

The authors of breaking changes take all risks of using experimental API in their own implementation, outside of public API surface.


Honestly, if this would mean “be careful, this might be full of bugs”, they shouldn’t release it anyway. @Experimental and @Internal usually denote an API that might change quickly (and possibly without notice)