<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harrypulvirenti</title>
    <description>The latest articles on DEV Community by Harrypulvirenti (@harrypulvirenti).</description>
    <link>https://dev.to/harrypulvirenti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F585631%2F9e923227-a4aa-460e-8a72-6cf3f669c085.jpeg</url>
      <title>DEV Community: Harrypulvirenti</title>
      <link>https://dev.to/harrypulvirenti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harrypulvirenti"/>
    <language>en</language>
    <item>
      <title>Gson migration made easy!</title>
      <dc:creator>Harrypulvirenti</dc:creator>
      <pubDate>Fri, 17 Dec 2021 14:04:54 +0000</pubDate>
      <link>https://dev.to/harrypulvirenti/gson-migration-made-easy-3b31</link>
      <guid>https://dev.to/harrypulvirenti/gson-migration-made-easy-3b31</guid>
      <description>&lt;p&gt;If you are here, you probably know how tedious it could be to deal with old code written with old deprecated tools that, for one reason or another, we never had the time to tackle correctly and try to find a strategy to remove it safely. Sometimes it could even be a nightmare if the code that you have to refactor is not a simple isolated feature.&lt;/p&gt;

&lt;p&gt;What if you have a giant network layer full of code that uses a deprecated tool like &lt;code&gt;Gson&lt;/code&gt; that is serving other features in your application and, in some way, you have to get rid of it without breaking half of your application?&lt;br&gt;
Well, I might not have a solution for the other kinds of migrations, but if you are dealing with this &lt;code&gt;Gson&lt;/code&gt; nightmare, I have a migration strategy that might save your day. Let's start by understanding why it is such a big problem if you want to remove &lt;code&gt;Gson&lt;/code&gt; from your codebase.&lt;/p&gt;

&lt;p&gt;Nowadays, modern Android applications, are written in Kotlin language, which is the standard de facto in terms of programming language for Android developers. The problem is that &lt;code&gt;Gson&lt;/code&gt; is written for Java so it lacks proper Kotlin support, especially for nullability.&lt;br&gt;
Since &lt;code&gt;Gson&lt;/code&gt; is built for Java it fails to understand the difference between nullable and non-nullable types of Kotlin. This means that if you have a DTO with some field declared as non-nullable and, one of these fields, is not returned in an API for any reason, your app will crash because of it.&lt;/p&gt;

&lt;p&gt;A standard solution for this problem is to declare all the fields of the DTO as nullable and then map them to a domain object checking first the presence or absence of any field manually.&lt;/p&gt;

&lt;p&gt;The result of this approach is a lot of boilerplate code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gson Object&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Domain Object&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;surname&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// throw an exception in a controlled manner &lt;/span&gt;
        &lt;span class="c1"&gt;// or use default value if possible&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Some field is null"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;address&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is an easy example but keep in mind that the more you complicate your network models the harder will become to deal with these kinds of checks.&lt;/p&gt;

&lt;p&gt;For example, let's try to complicate a bit the previous code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gson Object&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this second example, if we want to map the &lt;code&gt;PeopleDTO&lt;/code&gt; object to the domain class, we have to check also the fields of the &lt;code&gt;AddressDTO&lt;/code&gt; class and so on if you add other nested objects in the response.&lt;/p&gt;

&lt;p&gt;You can easily understand that this approach can carry on a lot of problems in terms of code complexity and boilerplate code in case of really complex network responses.&lt;/p&gt;

&lt;p&gt;Now that we understood the problem let's assume that we want to migrate our network layer to a more Kotlin friendly deserializer like &lt;strong&gt;Kotlinx Serialization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The DTO in our first example after the migration will be something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Kotlinx Serialization Object&lt;/span&gt;
&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is an easy change to do, but for complex network responses with many nested objects, this can result in giant PRs with hundreds of files changed only for the migration of a single call.&lt;br&gt;
And, trust me, once you start with the first object of the call these things will never end.&lt;br&gt;
It's like opening Pandora's box.&lt;br&gt;
And the more files are changed the higher is the risk of introducing some bug.&lt;/p&gt;

&lt;p&gt;Also, we didn’t mention that technically you should migrate every network call inside your Retrofit interface to switch to a new deserializer.&lt;br&gt;
Luckily, also for this problem, there are some strategies that you can adopt to migrate the responses call-by-call instead of migrating everything in once, but this is another problem (let me know in the comments if you want to read another article from me about this topic).&lt;/p&gt;

&lt;p&gt;Well, as I said previously, this is a nightmare.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FMcmLoTZCMUkoZGPXU6%2Fgiphy.gif%3Fcid%3Decf05e47vuw23ppyjg5aaw58n3v0u70r9bfdrre4eu2j3q62%26rid%3Dgiphy.gif%26ct%3Dg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FMcmLoTZCMUkoZGPXU6%2Fgiphy.gif%3Fcid%3Decf05e47vuw23ppyjg5aaw58n3v0u70r9bfdrre4eu2j3q62%26rid%3Dgiphy.gif%26ct%3Dg" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a simple and sustainable strategy that we can apply to perform the migration.&lt;/p&gt;

&lt;p&gt;If we compare the &lt;code&gt;GSON&lt;/code&gt; version of the DTOs with the &lt;code&gt;Kotlinx Serialization&lt;/code&gt; one, we might see some important differences: we have a lot of dirty DTOs classes with a lot of nullable fields that are not ready to be used with &lt;code&gt;Kotlinx Serialization&lt;/code&gt; and a lot of checks that we are performing on these classes to see if what we received from the network is well-formed or not.&lt;/p&gt;

&lt;p&gt;What we can do here is to migrate each DTO data class separately with the help of a custom &lt;strong&gt;JsonDeserializer&lt;/strong&gt; and, using some extensions utils, performs all the checks that we were doing on the dirty DTOs class inside the deserializer.&lt;/p&gt;

&lt;p&gt;Looks too complicated? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy39mxkzkzof8lb4ye1sl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy39mxkzkzof8lb4ye1sl.gif" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't worry it will be easier than expected when we will see this approach in action so let's check the code!&lt;/p&gt;

&lt;p&gt;Here we have the two classes that we want to migrate to &lt;code&gt;Kotlinx Serialization&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gson Object&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first step should be to update our two classes marking the fields as nullable only when there is an optional field and not everywhere.&lt;br&gt;
So after this first step, our classes should look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gson Object&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we have to create a custom deserializer for each DTO data class that we want to migrate:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonDeserializer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonDeserializer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;typeOfT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonDeserializationContext&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;PersonDTO&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asJsonObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;surname&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"surname"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deserializeAddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deserializeAddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonDeserializationContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getOrNull&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddressDeserializer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonDeserializer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;typeOfT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonDeserializationContext&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;AddressDTO&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asJsonObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;street&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These two deserializers are responsible for converting the received JSON to the desired DTO class checking that all the required fields are present.&lt;br&gt;
But as you can see the code is not that complicated, right?&lt;br&gt;
Well, this is because here I'm using some utils to simplify all the dirty work that we have to do in terms of checks and in particular I'm talking about the functions getNotNull, getOrNull and getType.&lt;/p&gt;

&lt;p&gt;Let's see the code of these functions in details:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNotNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;getOrNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonParseException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$memberName should be not null but is not present in the response or is null"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asJsonObject&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;JsonArray&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asJsonArray&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;JsonPrimitive&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asJsonPrimitive&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asBoolean&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asInt&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;asLong&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonParseException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Item type not supported"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toKotlinNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;JsonElement&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memberName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;takeIf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isJsonNull&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;TypeToken&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As you can see from the utils in the snippet, the only thing done is just to ensure that, the desired type of the field, is not null and, if yes, the field is extracted and cast to the specific requested type.&lt;/p&gt;

&lt;p&gt;Now that we have the custom deserializers implemented, the last thing that we need to do is to register both of them in the &lt;code&gt;Gson&lt;/code&gt; instance that we are using with &lt;code&gt;Retrofit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To do so, we can implement and use an extension function like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;GsonBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerDeserializers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;registerTypeAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PersonDTO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PersonDeserializer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTypeAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AddressDTO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AddressDeserializer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;gsonInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Gson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;GsonBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerDeserializers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that's it!&lt;br&gt;
In this way, you can easily migrate every single DTO in a Kotlin friendly version in a separate PR without changing a lot of classes.&lt;/p&gt;

&lt;p&gt;Once you are finished with the migration of all the DTO classes in your data layer, to start using &lt;code&gt;Kotlinx Serialization&lt;/code&gt;, you just have to add the &lt;code&gt;@Serializable&lt;/code&gt; annotation in all the DTO and replace the &lt;code&gt;Gson&lt;/code&gt; instance used in Retrofit with &lt;code&gt;Kotlinx Serialization&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All the custom deserializers that we implemented can be now deleted because no longer needed.&lt;/p&gt;

&lt;p&gt;If you reached this step congratulations!&lt;br&gt;
You successfully migrated your data layer to &lt;code&gt;Kotlinx Serialization&lt;/code&gt; without (I hope) going crazy!&lt;/p&gt;

&lt;p&gt;You can find all the provided code snippets in the following repository separated into different branches (one per step) as well as tests for all the custom deserializers.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Harrypulvirenti" rel="noopener noreferrer"&gt;
        Harrypulvirenti
      &lt;/a&gt; / &lt;a href="https://github.com/Harrypulvirenti/GsonMigration" rel="noopener noreferrer"&gt;
        GsonMigration
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample repository for a practical strategy to remove Gson from your project.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Gson Migration Strategy - Practical guide&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;In this repository, you will find the code examples of a migration strategy from &lt;code&gt;Gson&lt;/code&gt; to &lt;code&gt;Kotlin x Serialization&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This strategy is detailed described in &lt;a href="https://dev.to/harrypulvirenti/gson-migration-made-easy-3b31" rel="nofollow"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The examples are split into different branches per step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix DTOs fields nullability&lt;/li&gt;
&lt;li&gt;Implement a Custom Deserializers&lt;/li&gt;
&lt;li&gt;Register the deserializers to the &lt;code&gt;Gson&lt;/code&gt; instance and deserializers tests&lt;/li&gt;
&lt;li&gt;Finalise the migration to &lt;code&gt;Kotlin x Serialization&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For details about the advantages of this strategy refer to the provided article above.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Harrypulvirenti/GsonMigration" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Hope that this article helped you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/QLKSt3wQqlj7a/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/QLKSt3wQqlj7a/giphy.gif" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gson</category>
      <category>techdebt</category>
      <category>migration</category>
      <category>datalayer</category>
    </item>
    <item>
      <title>Let's Navigate</title>
      <dc:creator>Harrypulvirenti</dc:creator>
      <pubDate>Mon, 08 Mar 2021 09:01:45 +0000</pubDate>
      <link>https://dev.to/harrypulvirenti/let-s-navigate-538o</link>
      <guid>https://dev.to/harrypulvirenti/let-s-navigate-538o</guid>
      <description>&lt;p&gt;As Android Engineers probably many of you have already approached the development of a multi-module project and, if not, please consider doing that an maybe check out this cool article by Joe Birch.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/google-developer-experts/modularizing-android-applications-9e2d18f244a0" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AJ0BoXIqZemyIW3V25DK6CQ.png" alt="Joe Birch"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/google-developer-experts/modularizing-android-applications-9e2d18f244a0" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Modularizing Android Applications | by Joe Birch | Google Developer Experts | Medium&lt;/h2&gt;
      &lt;h3&gt;Joe Birch ・ &lt;time&gt;Sep 30, 2018&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;If you already had some experience with this topic, you probably know that one of the most challenging problems of a multi-module project is how to approach the &lt;strong&gt;navigation&lt;/strong&gt; between various feature modules.&lt;/p&gt;

&lt;p&gt;There are tons of possible approaches around this topic and here I'm going to talk about one based on &lt;strong&gt;Navigation Component&lt;/strong&gt; from Google.&lt;/p&gt;

&lt;p&gt;Suppose that you have this situation:&lt;br&gt;
One &lt;strong&gt;Application Module&lt;/strong&gt; and a few other &lt;strong&gt;feature modules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2524bipqvkdwi2dijanu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2524bipqvkdwi2dijanu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point let's say that we want to navigate from &lt;code&gt;feature 1&lt;/code&gt; -&amp;gt; &lt;code&gt;feature 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first thing that you maybe be tempted to do is to introduce one new dependency in the Gradle from &lt;code&gt;feature 1&lt;/code&gt; -&amp;gt; &lt;code&gt;feature 2&lt;/code&gt; in order to see the destination that you want to reach.&lt;/p&gt;

&lt;p&gt;Well, this is not a good practice because later on time can happen that you will have the need to navigate back from &lt;code&gt;feature 1&lt;/code&gt; &amp;lt;- &lt;code&gt;feature 2&lt;/code&gt; and, once you introduced this new dependency, you will have a circular dependency in your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/fSkpUE72ynxPsKVNYW/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/fSkpUE72ynxPsKVNYW/giphy.gif" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we understood why it's so complex to navigate between different modules we can try to find some good solution to this problem with the help of &lt;strong&gt;Navigation Component&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I'm going to assume that you have, at least, a basic knowledge of what is &lt;em&gt;Navigation Component&lt;/em&gt; and what is capable to do.&lt;br&gt;
Trying to describe it in the simplest way possible, we can say that &lt;em&gt;Navigation Component&lt;/em&gt; is a tool that allows you to declare all your &lt;code&gt;destinations&lt;/code&gt; and &lt;code&gt;routes&lt;/code&gt; in one &lt;code&gt;XML&lt;/code&gt;, called &lt;code&gt;Navigation Graph&lt;/code&gt;, and provides a high-level API to navigate between them.&lt;br&gt;
One feature that, in this case, can help us a lot is the ability to split the content of one monolithic navigation graph into multiple ones.&lt;/p&gt;

&lt;p&gt;Now that we have these concepts, let's summarize all the goals that we want to achieve with our navigation implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Every feature should be responsible for its own graph.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Every feature should be able to reach all the available destinations inside the app.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Avoid Circular Dependencies.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Well! Now it's finally time to code!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrahp870nh1gj444fn89.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrahp870nh1gj444fn89.gif" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first thing that we have to do is to declare all the &lt;code&gt;Navigation Graphs&lt;/code&gt; for every feature so we will end in a situation like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0z5m0zsiokgrpmosw5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0z5m0zsiokgrpmosw5y.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this way, inside the &lt;code&gt;main_graph.xml&lt;/code&gt;, should be possible to do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;include app:graph="@navigation/feature_1_graph.xml" /&amp;gt;

&amp;lt;include app:graph="@navigation/feature_2_graph.xml" /&amp;gt;

&amp;lt;include app:graph="@navigation/feature_3_graph.xml" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Doing so, every feature will be responsible for its own internal &lt;code&gt;Navigation Graph&lt;/code&gt; and should expose only the entry points needed to navigate to the feature.&lt;br&gt;
All the &lt;code&gt;sub-graphs&lt;/code&gt; are then collected by the application and included inside the &lt;code&gt;main_graph&lt;/code&gt; to allow all the features to perform the navigation.&lt;/p&gt;

&lt;p&gt;Now we have only another problem: &lt;strong&gt;How to perform the navigation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to navigate with &lt;em&gt;Navigation Component&lt;/em&gt; we need two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The destination that we want to reach is included in the &lt;code&gt;main_graph.xml&lt;/code&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The ID of the entry point of the destination.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first point is done so we need to focus on the second one.&lt;/p&gt;

&lt;p&gt;To solve this problem we can use one small trick:&lt;br&gt;
&lt;strong&gt;Declare in advance all the entry points IDs in a shared place&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;destinations.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;resources&amp;gt;

    &amp;lt;!--
    This resource file is the place where you should declare public navigable destinations inside the app
    --&amp;gt;

    &amp;lt;item name="feature1Fragment" type="id" /&amp;gt;
    &amp;lt;item name="feature2Fragment" type="id" /&amp;gt;
    &amp;lt;item name="feature3Fragment" type="id" /&amp;gt;

&amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this way, we can use the predeclared IDs to later provide the implementation of the destinations and/or new routes that are using the IDs of the destinations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;feature_1_graph.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/feature_1_graph"
    app:startDestination="@id/feature1Fragment"&amp;gt;

    &amp;lt;fragment
        android:id="@id/feature1Fragment"
        android:name="com.navigation.sample.feature1.Feature1Fragment"
        android:label="Feature1Fragment"&amp;gt;

        &amp;lt;action
            android:id="@+id/feature1ToFeature2"
            app:destination="@id/feature2Fragment" /&amp;gt;

    &amp;lt;/fragment&amp;gt;

&amp;lt;/navigation&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At this point your Gradle dependency graph should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshvvva8kp6ab0mr84uq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshvvva8kp6ab0mr84uq4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's check our goals list to see how many progress we did so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Every feature should be responsible for its own graph.&lt;/em&gt; ✅&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Every feature should be able to reach all the available destinations inside the app.&lt;/em&gt; ✅&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Avoid Circular Dependencies.&lt;/em&gt; ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can understand from the goals list, the solution that we implemented is satisfying all the requirements that we fixed but there is one thing that we can still improve optionally.&lt;/p&gt;

&lt;p&gt;This solution has one requirement:&lt;br&gt;
Every time that we want to add or remove a feature we have to manually modify both the &lt;code&gt;main_graph.xml&lt;/code&gt; and the &lt;code&gt;destinations.xml&lt;/code&gt; to update the included features properly.&lt;/p&gt;

&lt;p&gt;Not a big problem in the end but since developers are lazy we can try to find a better solution for this problem. 😝&lt;/p&gt;

&lt;p&gt;But what can we do about it? 🤔&lt;/p&gt;

&lt;p&gt;The idea here is to collect all the &lt;code&gt;sub-graphs&lt;/code&gt; references and include them programmatically to the &lt;code&gt;main_graph.xml&lt;/code&gt; at runtime.&lt;/p&gt;

&lt;p&gt;To reach this result we are going to use the &lt;code&gt;Dependency Injection&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here doesn't matter if you prefer to use Dagger2, Koin or whatever.&lt;br&gt;
The important thing is that in every feature you should be able to expose the navigation graph reference of the feature outside of its own module.&lt;/p&gt;

&lt;p&gt;Let's see a quick sample:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Module
object Feature1GraphModule {

    @Provides
    @IntoSet
    fun provideGraphReference() = R.navigation.feature_1_graph
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, you should be able to access all these graphs references and include them in the &lt;code&gt;main_graph&lt;/code&gt; with a code like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val mainGraph = navController.navInflater.inflate(R.navigation.main_graph)

// subGraphsIDs is the set of all the sub-graphs collected by Dagger multi-binding

subGraphsIDs
   .map { graphId -&amp;gt;
      navController.navInflater.inflate(graphId)
   }
   .forEach { graph-&amp;gt;
      mainGraph.addAll(graph)
   }

navController.graph = mainGraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This operation should be performed in your main &lt;code&gt;NavController&lt;/code&gt; in order to allow the entire app to see your &lt;code&gt;sub-graphs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, to wrap up let's check our Gradle dependency graph one last time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9f76sc1zyiy4e7zeodr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9f76sc1zyiy4e7zeodr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see now we have a new module called &lt;code&gt;main_activity_feature&lt;/code&gt;.&lt;br&gt;
This is where your &lt;code&gt;MainActivity&lt;/code&gt;/&lt;code&gt;Main NavController&lt;/code&gt; should be located.&lt;br&gt;
In this module, you should perform the setup that I described before.&lt;/p&gt;

&lt;p&gt;Another small difference is that now the &lt;code&gt;app&lt;/code&gt; module doesn’t know anything about the &lt;code&gt;main_graph&lt;/code&gt;, about the navigation or anything else.&lt;br&gt;
Now the &lt;code&gt;app&lt;/code&gt; module is depending on the feature modules only for collecting all the &lt;code&gt;Dependency Injection Modules&lt;/code&gt; and this is a big plus in terms of code maintenance because, in this way, every time you need to add or remove a feature you just need to provide the correct DI setup and you are done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/xUPOqo6E1XvWXwlCyQ/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/xUPOqo6E1XvWXwlCyQ/giphy.gif" alt="gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A working sample of this navigation approach can be found in my personal project here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Harrypulvirenti" rel="noopener noreferrer"&gt;
        Harrypulvirenti
      &lt;/a&gt; / &lt;a href="https://github.com/Harrypulvirenti/TimeToPlay" rel="noopener noreferrer"&gt;
        TimeToPlay
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I hope that you liked this small post and thanks for reading till here!&lt;/p&gt;

</description>
      <category>android</category>
      <category>navigation</category>
      <category>di</category>
      <category>multimodule</category>
    </item>
  </channel>
</rss>
