<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kotlinx Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/kotlinx/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Tue, 12 Dec 2023 06:00:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>kotlinx Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>kotlinx.serialization in Kotlin- All You Need To Know</title>
		<link>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/</link>
					<comments>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Tue, 12 Dec 2023 06:00:00 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[kotlinx]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9008417</guid>

					<description><![CDATA[<p>In this article, we will cover the most important scenarios of kotlinx.serialization in Kotlin and how to use it to your advantage.</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you are working with Kotlin, then it is a matter of time before you will face a need to <strong>serialize </strong>and <strong>deserialize </strong>your data.&nbsp;In this topic, I am going to cover the most important scenarios of <strong>kotlinx.serialization in Kotlin</strong> and how to use it to your advantage in your projects.</p>



<p>If you haven&#8217;t heard about it, then Kotlin Serialization is a <strong>cross-platform</strong> and multi-format framework built for this specific needs. It can be used with practically any Kotlin-based project, such as Android applications, Ktor applications, and Multiplatform (Common, JS, Native).&nbsp;</p>



<h2 class="wp-block-heading" id="h-setting-up">Setting Up</h2>



<p>To set up kotlinx.serialization in our project, we must add the following lines in your <strong>build.gradle.kts</strong>. </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">plugins {

    kotlin("jvm") version "1.9.20" // or kotlin("multiplatform")

    kotlin("plugin.serialization") version "1.9.20"

}</pre>



<p>This will add the plugin. </p>



<p>Following, let&#8217;s add the implementation of the library itself:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">repositories {

    mavenCentral()

}

dependencies {

    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1")

}</pre>



<p>Now we&#8217;re ready to go!</p>



<h2 class="wp-block-heading" id="h-basic-serialization">Basic Serialization</h2>



<h3 class="wp-block-heading" id="h-simple-objects">Simple Objects</h3>



<p>You may not used this library yourself but you might have seen a <strong>@Serializable</strong> annotation before. </p>



<p>This is practically all we&#8217;re going to need to set up a serialization for a particular class, like this:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Now, to manually serialize it, we only need to use a <strong>Json.encodeToString()</strong>. </p>



<p>For example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>The output would be the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice"}</pre>



<p>On the other hand, to deserialize something, we&#8217;ll use <strong>Json.decodeFromString()</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """  
  {
    "userId": 1,
    "userName":"Alice"
  }
"""  

println(
  Json.decodeFromString(
    User.serializer(), 
    data
  )
)</pre>



<p>The output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=Alice)</pre>



<p>kotlinx.serialization has also some useful functions to work with <strong>InputStream</strong> rather than with <strong>String</strong>. However, they are experimental at the moment and require using <strong>@OptIn(ExperimentalSerializationApi::class)</strong>.  </p>



<p>What am I talking about here? The <strong>Json.encodeFromStream()</strong> and <strong>Json.decodeFromStream()</strong>, which come in handy when we are dealing with Files.</p>



<p>Let&#8217;s take a look at how we can get data from the file without reading it and converting it to String. It saves lots of computation time, particularly on a big scale:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@OptIn(ExperimentalSerializationApi::class)
fun deserializeFile(file: File): User {
  return Json.decodeFromStream(
    User.serializer(),
    file.inputStream()
  )
}</pre>



<p>Similarly, to encode it to a file we will use the <strong>encodeToStream</strong>:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@OptIn(ExperimentalSerializationApi::class)
fun serializeFile(user: User, file: File) {
  Json.encodeToStream(
    User.serializer(),
    user,
    file.outputStream()
  )
}</pre>



<h3 class="wp-block-heading" id="h-nested-referenced-objects">Nested(Referenced) Objects</h3>



<p>As the next step, let&#8217;s talk about <strong>nested serialization</strong>. </p>



<p>Highly likely, that some of your classes have a property that is another class. </p>



<p>In such a case, there is practically no difference from the previous section, just all of our classes have to have a <strong>@Serializable</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Profile(
  val id: Int,
  val user: User
)

@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Let&#8217;s check it out like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val originalProfile = Profile(
  id = 123, 
  user = User(userId = 1, userName = "Alice")
)
  
println( 
  Json.encodeToString(
    Profile.serializer(), 
    originalProfile
  )
)  

val jsonString = """  
  {
    "id":123,
    "user": {
      "userId": 1,
      "userName":"Alice"
    }
  }
"""  

val deserializedProfile = Json.decodeFromString(
  Profile.serializer(), 
  jsonString
)
  
println(deserializedProfile)</pre>



<p>The output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":123,"user":{"userId":1,"userName":"Alice"}}
Profile(id=123, user=User(userId=1, userName=Alice))</pre>



<h3 class="wp-block-heading" id="h-lists">Lists</h3>



<p>To serialize the whole List, we can use the <strong>ListSerializer</strong> constructor to create a serializer for any type of list, as long as <strong>we provide a serializer for the element type</strong>. </p>



<p>For example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val originalUsers = listOf(
  User(userId = 1, userName = "Alice"),
  User(userId = 2, userName = "Bob")
)  

println(
  Json.encodeToString(
    ListSerializer(User.serializer()), 
    originalUsers
  )
)  

val jsonString = """ 
  [
    {"userId":1,"userName":"Alice"},
    {"userId":2,"userName":"Bob"}
  ] 
"""  

val deserializedUsers = Json.decodeFromString(
  ListSerializer(User.serializer()), 
  jsonString
)  

println(deserializedUsers)</pre>



<p>That code will give us:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[{"userId":1,"userName":"Alice"},{"userId":2,"userName":"Bob"}]
[User(userId=1, userName=Alice), User(userId=2, userName=Bob)]</pre>



<h3 class="wp-block-heading" id="h-generics">Generics</h3>



<p>Basically, generics serialization works the same as nested objects. </p>



<p>The kotlinx.serialization has type-polymorphic behavior, which means that JSON relies on the actual type parameter. It will be compiled successfully if the actual generic type is a serializable class. </p>



<p>To check that, let&#8217;s modify our classes:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Profile&lt;T>(
  val id: T,
  val user: Wrapper&lt;T>
)

@Serializable
data class Wrapper&lt;T>(val contents: T)</pre>



<p>Now we can check how it will work with different T for user fields:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val profile1 = Profile(
  1, 
  Wrapper(
    User(userId = 1, userName = "Alice")
  )
)  
val profile2 = Profile(
  2, 
  Wrapper(42)
)  
  
val jsonProfile1 = Json.encodeToString(profile1)  
val jsonProfile2 = Json.encodeToString(profile2)  
  
println(jsonProfile1)  
println(jsonProfile2)  
  
val jsonString1 = """ 
  {
    "id": 1,
    "user": {
      "contents": {
        "userId": 1,
        "userName": "Alice"
      }
    }
  } 
"""  
val jsonString2 = """ 
  {
    "id": 2,
    "user": {
      "contents": 42
    }
  } 
"""  
  
val deserializedProfile1 = Json.decodeFromString(
  Profile.serializer(
    User.serializer()
  ),
  jsonString1
)  
val deserializedProfile2 = Json.decodeFromString(
  Profile.serializer(
    Int.serializer()
  ), 
  jsonString2
)  
  
println(deserializedProfile1)  
println(deserializedProfile2)</pre>



<p>There will be the following output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":1,"user":{"contents":{"userId":1,"userName":"Alice"}}}
{"id":2,"user":{"contents":42}}
Profile(id=1, user=Wrapper(contents=User(userId=1, userName=Alice)))
Profile(id=2, user=Wrapper(contents=42))</pre>



<h2 class="wp-block-heading" id="h-customizing-serialization-and-deserialization">Customizing serialization and deserialization</h2>



<p>In this paragraph, we are gonna talk about making your objects a little bit appealing with variable behavior to adjust our specific needs.</p>



<h3 class="wp-block-heading" id="h-custom-names">Custom names</h3>



<p>As you have noticed, the basic name of a field is taken by default. </p>



<p>To create a custom name, the only thing we need is a <strong>@SerialName</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  @SerialName("id") val userId: Int,
  @SerialName("login") val userName: String
)</pre>



<p>Now let&#8217;s use it as we used in the example at the beginning:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>We&#8217;ll get:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":1,"login":"Alice"}</pre>



<p>But we must be careful- this works both ways. </p>



<p>After the change, we must make sure that the incoming JSON contains the names that we mentioned in the <strong>@SerialName</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """{"id":1,"login":"Alice"}"""         //correct
val data = """{"userId":1,"userName":"Alice"}"""  //wrong</pre>



<h3 class="wp-block-heading" id="h-default-values">Default values</h3>



<p>Now things get a little bit trickier. Default values are not encoded by default. </p>



<p>So, if we want them to, we need the <strong>@EncodeDefault</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String = "user"
)</pre>



<p>This way, we could omit a userName and the serialization library will use the default value:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1)
println(
  Json.encodeToString(data)
)</pre>



<p>Let&#8217;s see:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"user"}</pre>



<p>Excellent, works as expected!</p>



<p>But here is a different situation. What if we want to deserialize a JSON with some optional fields? </p>



<p>For it to compile properly, we must provide a default value for these fields:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String = "user"
)</pre>



<p>Now we can deserialize an object like this:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """
  {
    "userId": 1
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>Output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=user)</pre>



<p>On the other hand, if we want an optional field to be present in JSON, we may use a <strong>@Required</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @Required val userName: String = "user"
)</pre>



<p>If we use this class with the code before, <strong>we will get an error</strong>, which can be useful in some scenarios:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Exception in thread &#8220;main&#8221; kotlinx.serialization.MissingFieldException: Field &#8216;userName&#8217; is required for type with serial name &#8216;com.example.User&#8217;, but it was missing</cite></blockquote>



<h3 class="wp-block-heading" id="h-nulls">Nulls</h3>



<p>Kotlin&#8217;s language is known for its type safety. The kotlinx.serialization knows it as well. </p>



<p>We cannot decode a null value into a non-nullable property or we get an exception. For example, for this class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>We cannot expect to serialize this object below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """
  {
    "userId": 1,
     "userName": null
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>It will result in an error.</p>



<p>To avoid it, we should do this instead:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String?
)</pre>



<p>This time, our result will be:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=null)</pre>



<p>As we can see, default values are not encoded by default. </p>



<p>So to get a missing property from JSON not as an optional but as a null value, we have to use <strong>@EncodeDefault</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String? = null
)</pre>



<p>That is what we&#8217;ll see for our class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":null}</pre>



<p>However, if we forget the annotation, this is what we will get:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1}</pre>



<h2 class="wp-block-heading" id="h-advanced-serialization">Advanced Serialization</h2>



<p>This section is probably what you are looking for if you have a complex project. </p>



<p>These are the most sophisticated tricks of kotlinx.serialization, but the most useful, though. And now we are going to understand how they work.</p>



<p>From now on everything becomes more complex. So we have to establish ground rules and basic terms. </p>



<h3 class="wp-block-heading" id="h-what-exactly-is-a-polymorphism">What Exactly Is a Polymorphism?</h3>



<p>Polymorphism in Kotlin is the ability of an object or a function to have different forms or behaviors depending on the context. A polymorphic object can belong to different classes and respond to the same method call in different ways. </p>



<p>There are two types of polymorphism in Kotlin: <strong>compile-time</strong> and <strong>run-time</strong>:</p>



<ul class="wp-block-list">
<li><strong>Compile-time</strong> polymorphism, also known as static polymorphism, is achieved through function overloading. It allows the name of functions, i.e., the signature, to be the same but return type or parameter lists to be different.</li>



<li><strong>Run-time </strong>polymorphism, or <strong>dynamic </strong>polymorphism, is achieved through function overriding and inheritance. In the run-time polymorphism, the compiler resolves a call to overload methods at the runtime.</li>
</ul>



<p>But there is more. For serialization, we are going to talk about different approaches. To serialize an object, we should know what that object is in the first place and can its behavior can be changed. So there are 2 more types of polymorphism:</p>



<ul class="wp-block-list">
<li><strong>Closed</strong> polymorphism means that the behavior of an object is fixed and cannot be changed by subclasses or external factors.</li>



<li><strong>Open</strong> polymorphism means that the behavior of an object can be modified or extended by subclasses or external factors.<br>This is how the library sees polymorphism for the most part.</li>
</ul>



<h3 class="wp-block-heading" id="h-the-practice-part">The Practice Part</h3>



<p>First things first, let&#8217;s talk about <strong>closed </strong>polymorphism in kotlinx.serialization. </p>



<p>The first and the most obvious thing to do is to make all of our classes serializable:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
open class User(
  val userId: Int,
  val userName: String?
)

@Serializable
@SerialName("admin")
class Admin(
  val adminId: Int,
  val adminName: String?,
  val adminRole: String
) : User(adminId, adminName)</pre>



<p>Let&#8217;s check it out:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Everything works as expected, our Admin is indeed a user:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice"}</pre>



<p>But what will happen if we try to serialize an Admin object:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Let&#8217;s find out:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice","adminId":1,"adminName":"Alice","adminRole":"Boss"}</pre>



<p>So you have to keep that in mind. This may be a bit odd.<br>Following this, I want to cover <strong>sealed classes</strong> as well. Not because I&#8217;m a huge fan of it, which I am, but because of its natural behavior (we know all of its children at the runtime) that helps our process:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
sealed class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()</pre>



<p>We are going to check our first scenario:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>As expected, now we know the type of our user beforehand:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}</pre>



<p>For a <strong>closed</strong> polymorphism, things get different. Now we have to create a <strong>SerializersModule</strong> and provide explicit subclasses that are to be serialized.</p>



<p>Let&#8217;s create an additional class to show this in action:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
abstract class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()

@Serializable
@SerialName("guest")
class Guest(
  override val userId: Int,
  override val userName: String?,
  val guestEmail: String?
) : User()</pre>



<p>Now comes the module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val module = SerializersModule {
  polymorphic(User::class) {
    subclass(Admin::class, Admin.serializer())
    subclass(Guest::class, Guest.serializer())
  }
}</pre>



<p>We&#8217;ve used a <strong>Json</strong> instance for our needs before. Now we have to create a specific instance with our module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val format = Json { serializersModule = module }</pre>



<p>With that done, let&#8217;s check it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )
  val guest: User = Guest(
    userId = 1,
    userName = "Alice",
    guestEmail = "guest@email.com"
  )

  println(format.encodeToString(admin))
  println(format.encodeToString(guest))
}</pre>



<p>And this time, we get the following results:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}
{"type":"guest","userId":1,"userName":"Alice","guestEmail":"guest@email.com"}</pre>



<p>We can serialize classes as long as we provide corresponding subclasses. </p>



<p>Of course, there is a lot to cover, for example, multiple superclasses or interfaces. But let&#8217;s stop here, maybe I&#8217;ll cover it explicitly in the other article. (Let me know if you are interested in this 🙂 ) </p>



<h3 class="wp-block-heading" id="h-custom-serializers">Custom serializers</h3>



<p>For some classes, happens that the default serialization method does not fulfill our needs. Or we want to create one that reflects a unique class utilization approach. For this purpose, <strong>custom serializers</strong> are our best friends. The most common examples are Date and Color. I&#8217;m gonna focus on Date.</p>



<p>Basically, there are 3 main parts of our custom serializer. Let&#8217;s check how the serializer for Date might look like:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>We can already see all the necessary parts.</p>



<ul class="wp-block-list">
<li>The <strong>serialize</strong> function is used to turn an object into a sequence of simple values. It takes an Encoder and a value as inputs. It calls the encodeXxx functions of the Encoder to make the sequence. There is a different encodeXxx function for each simple type.</li>



<li>The <strong>deserialize</strong> function is used to turn a sequence of simple values back into an object. It takes a Decoder as input and returns a value. It calls the decodeXxx functions of the Decoder to get the sequence. These functions match the encodeXxx functions of the Encoder.</li>



<li>The <strong>descriptor</strong> property is used to tell how the encodeXxx and decodeXxx functions work. This helps the format to know what methods to use. Some formats can also use it to make a schema for the data.</li>
</ul>



<p>For our purposes, we can simplify the class. If there is no particular need in the <strong>descriptor</strong>, we can use a <strong>@Serializer(forClass = …)</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializer(forClass = Date::class)
object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>To implement our custom serializer we should use a <strong>@Serializable(with = …)</strong> annotation for the corresponding property:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Event(
  val name: String,
  @Serializable(with = DateSerializer::class)
  val date: Date
)</pre>



<p>Let&#8217;s see that in action:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val event = Event("Birthday Party", Date())  

val json = Json.encodeToString(event)  

println(json)</pre>



<p>With the result:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"name":"Birthday Party","date":"2023-11-23 T 17:12:36.069+0300"}</pre>



<p>As we can see, it has successfully been serialized to the desired date format.</p>



<h3 class="wp-block-heading" id="h-contextual-serialization">Contextual serialization</h3>



<p>Sometimes we need to change how we write objects as JSON at run-time, not just at compile-time, as we spoke before. This is called contextual serialization. </p>



<p>We can use the <strong>@Contextual</strong> annotation on a class or a property to tell Kotlin to use the ContextualSerializer class. This class will choose the right serializer for the object based on the context. We are going to use the previous serializer:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object DateAsStringSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>And our class will be looking like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Event(
  val name: String,
  @Contextual val date: Date
)</pre>



<p>Now we need to create a <strong>SerializersModule</strong> in which we need to specify a serializers should be used for our contextually-serializable classes. </p>



<p>We can simply wrap our serializer in <strong>contextual</strong> function inside the module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val module = SerializersModule {
  contextual&lt;Date>(DateAsStringSerializer)
}  </pre>



<p>Now we create a format out of Json with our module: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val format = Json { serializersModule = module }</pre>



<p>Using our format of <strong>Json</strong> earlier, we&#8217;ll get our run-time serialization:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val event = Event("Birthday Party", Date())  

val json = format.encodeToString(event)  

println(json)</pre>



<p>With an expected output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"name":"Birthday Party","date":"2023-11-23 T 23:20:03.421+0300"}</pre>



<p></p>



<h2 class="wp-block-heading" id="h-kotlinx-serialization-summary">kotlinx.serialization Summary</h2>



<p>And that&#8217;s all for this article about <strong>serialization in Kotlin with kotlinx.serialization</strong>.</p>



<p>In the upcoming articles, we will get back to this topic and learn how to apply this knowledge with Ktor, so don&#8217;t forget to join the <a href="https://codersee.com/newsletter/">free newsletter</a> to not miss it!</p>



<p>Lastly, if you would like to learn more about kotlinx, then you can find lots of useful information on the official documentation of <a href="https://github.com/Kotlin/kotlinx.serialization" target="_blank" rel="noreferrer noopener">kotlinx</a>.&nbsp;</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-05-13 17:08:28 by W3 Total Cache
-->